mame/src/devices/cpu/e132xs/e132xsdrc_ops.hxx
Vas Crabb eed05ed158 cpu/e132xs: Emulate more exceptions, more recompiler optimisation.
Emulate pointer error exception on load/store and range error exception
on store signed byte/half-word.

Further optimised code generation for MOV and MOVI.  These are very hot,
so this alone gains a further 2% performance or so in the dgPIX games.

Also some other miscellaneous cleanup.
2025-03-31 04:38:51 +11:00

4223 lines
128 KiB
C++

// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#ifndef MAME_CPU_E132XS_E132XSDRC_OPS_HXX
#define MAME_CPU_E132XS_E132XSDRC_OPS_HXX
#pragma once
#include "e132xs.h"
constexpr uint32_t WRITE_ONLY_REGMASK = (1 << BCR_REGISTER) | (1 << TPR_REGISTER) | (1 << FCR_REGISTER) | (1 << MCR_REGISTER);
uint32_t hyperstone_device::generate_get_const(const opcode_desc *desc)
{
const uint16_t imm_1 = m_pr16(desc->pc + 2);
if (imm_1 & 0x8000)
{
const uint16_t imm_2 = m_pr16(desc->pc + 4);
uint32_t imm = imm_2 | (uint32_t(imm_1 & 0x3fff) << 16);
if (imm_1 & 0x4000)
imm |= 0xc0000000;
return imm;
}
else
{
uint32_t imm = imm_1 & 0x3fff;
if (imm_1 & 0x4000)
imm |= 0xffffc000;
return imm;
}
}
uint32_t hyperstone_device::generate_get_immediate_s(const opcode_desc *desc)
{
const uint16_t op = desc->opptr.w[0];
switch (op & 0xf)
{
case 0:
return 16;
case 1:
return (uint32_t(m_pr16(desc->pc + 2)) << 16) | m_pr16(desc->pc + 4);
case 2:
return m_pr16(desc->pc + 2);
case 3:
return 0xffff0000 | m_pr16(desc->pc + 2);
default:
return s_immediate_values[op & 0xf];
}
}
uint32_t hyperstone_device::generate_get_pcrel(const opcode_desc *desc)
{
const uint16_t op = desc->opptr.w[0];
if (op & 0x80)
{
const uint16_t next = m_pr16(desc->pc + 2);
uint32_t offset = (uint32_t(op & 0x7f) << 16) | (next & 0xfffe);
if (next & 1)
offset |= 0xff800000;
return offset;
}
else
{
uint32_t offset = op & 0x7e;
if (op & 1)
offset |= 0xffffff80;
return offset;
}
}
std::pair<uint16_t, uint32_t> hyperstone_device::generate_get_d_code_dis(const opcode_desc *desc)
{
const uint16_t next_1 = m_pr16(desc->pc + 2);
const uint16_t d_code = (next_1 & 0x3000) >> 12;
uint32_t dis;
if (next_1 & 0x8000)
{
const uint16_t next_2 = m_pr16(desc->pc + 4);
dis = next_2 | (uint32_t(next_1 & 0x0fff) << 16);
if (next_1 & 0x4000)
dis |= 0xf0000000;
}
else
{
dis = next_1 & 0xfff;
if (next_1 & 0x4000)
dis |= 0xfffff000;
}
return std::make_pair(d_code, dis);
}
inline void hyperstone_device::generate_add_dis(drcuml_block &block, compiler_state &compiler, uml::parameter dst, uml::parameter base, uint32_t dis, unsigned alignment)
{
const uint32_t mask = ~uint32_t(alignment - 1);
if (base.is_immediate())
{
UML_MOV(block, dst, (base.immediate() + (dis & mask)) & mask);
}
else if (dis)
{
UML_ADD(block, dst, base, dis & mask);
if (alignment > 1)
UML_AND(block, dst, dst, mask);
}
else if (alignment > 1)
{
UML_AND(block, dst, base, mask);
}
else if (dst != base)
{
UML_MOV(block, dst, base);
}
}
void hyperstone_device::generate_get_global_register_high(drcuml_block &block, compiler_state &compiler, uint32_t code, uml::parameter dst)
{
// Expects cycles in I7 (cleared after use)
code |= 0x10;
if (code == TR_REGISTER)
{
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I7);
UML_MOV(block, I7, 0);
UML_SHR(block, dst, mem(&m_core->tr_clocks_per_tick), 1);
UML_CMP(block, mem(&m_core->icount), dst);
UML_MOVc(block, uml::COND_BE, dst, 0);
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), dst);
UML_CALLC(block, &c_funcs::compute_tr, this);
UML_MOV(block, dst, mem(&m_core->tr_result));
}
else
{
UML_MOV(block, dst, mem(&m_core->global_regs[code]));
}
}
void hyperstone_device::generate_set_global_register(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint32_t dst_code)
{
// TODO: this function should be refactored away
// Expects value in I5, clobbers I6 when setting high registers
if (dst_code < 16)
{
if (dst_code == 0)
{
UML_AND(block, DRC_PC, I5, ~1);
}
else if (dst_code == 1)
{
// TODO: privilege check on setting L in user mode
UML_ROLINS(block, DRC_SR, I5, 0, 0x0000ffff);
UML_AND(block, DRC_SR, DRC_SR, ~0x40);
}
else
{
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
}
}
else
{
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I7);
UML_MOV(block, I7, 0);
if ((dst_code <= 17) || (dst_code == BCR_REGISTER) || (dst_code == WCR_REGISTER))
{
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
}
else if (dst_code < BCR_REGISTER)
{
// SP or UB
UML_AND(block, mem(&m_core->global_regs[dst_code]), I5, ~uint32_t(3));
}
else if (dst_code == TPR_REGISTER)
{
const int skip_compute_tr = compiler.next_label();
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
UML_TEST(block, I5, 0x80000000);
UML_JMPc(block, uml::COND_NZ, skip_compute_tr);
UML_CALLC(block, &c_funcs::compute_tr, this);
UML_CALLC(block, &c_funcs::update_timer_prescale, this);
UML_LABEL(block, skip_compute_tr);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
}
else if (dst_code == TCR_REGISTER)
{
const int done = compiler.next_label();
UML_MOV(block, I6, mem(&m_core->global_regs[dst_code]));
UML_CMP(block, I6, I5);
UML_JMPc(block, uml::COND_E, done);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
UML_LABEL(block, done);
}
else if (dst_code == TR_REGISTER)
{
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
UML_MOV(block, mem(&m_core->tr_base_value), I5);
UML_CALLC(block, &c_funcs::total_cycles, this);
UML_DMOV(block, mem(&m_core->tr_base_cycles), mem(&m_core->numcycles));
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
}
else if (dst_code == ISR_REGISTER)
{
// ISR - read-only
}
else if (dst_code == FCR_REGISTER)
{
const int skip_adjust_timer = compiler.next_label();
UML_MOV(block, I6, mem(&m_core->global_regs[dst_code]));
UML_XOR(block, I6, I6, I5);
UML_TEST(block, I6, 0x80000000);
UML_JMPc(block, uml::COND_Z, skip_adjust_timer);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
UML_LABEL(block, skip_adjust_timer);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
}
else if (dst_code == MCR_REGISTER)
{
UML_ROLAND(block, I6, I5, 20, 0x7);
UML_LOAD(block, I6, (void *)s_trap_entries, I6, SIZE_DWORD, SCALE_x4);
UML_MOV(block, mem(&m_core->trap_entry), I6);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
}
else
{
// reserved register - just store the value
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
}
}
}
void hyperstone_device::generate_set_global_register_low(drcuml_block &block, compiler_state &compiler, uint32_t dst_code, uml::parameter src)
{
// clobbers I4 when setting SR
if (dst_code == PC_REGISTER)
{
UML_AND(block, DRC_PC, src, ~uint32_t(1));
}
else if (dst_code == SR_REGISTER)
{
UML_MOV(block, I4, DRC_SR);
if (compiler.supervisor_mode() || (src.is_immediate() && !(src.immediate() & L_MASK)))
{
UML_ROLINS(block, I4, src, 0, 0x0000ffff);
UML_AND(block, I4, I4, ~0x40); // keep reserved bit clear
}
else
{
const int no_exception = compiler.next_label();
UML_TEST(block, I4, L_MASK);
UML_JMPc(block, uml::COND_NZ, no_exception);
if (src.is_immediate())
{
UML_ROLINS(block, I4, src.immediate() & ~0x40, 0, 0x0000ffff); // keep reserved bit clear
}
else
{
UML_TEST(block, src, L_MASK);
UML_JMPc(block, uml::COND_Z, no_exception);
UML_ROLINS(block, I4, src, 0, 0x0000ffff);
UML_AND(block, I4, I4, ~0x40); // keep reserved bit clear
}
UML_MOV(block, DRC_SR, I4);
UML_EXH(block, *m_exception, TRAPNO_PRIVILEGE_ERROR);
UML_LABEL(block, no_exception);
if (src.is_immediate())
{
UML_ROLINS(block, I4, src.immediate() & ~0x40, 0, 0x0000ffff); // keep reserved bit clear
}
else
{
UML_ROLINS(block, I4, src, 0, 0x0000ffff);
UML_AND(block, I4, I4, ~0x40); // keep reserved bit clear
}
}
UML_MOV(block, DRC_SR, I4);
}
else
{
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
}
}
void hyperstone_device::generate_set_global_register_high(drcuml_block &block, compiler_state &compiler, uint32_t dst_code, uml::parameter src)
{
// Expects cycles in I7 (cleared after use), clobbers I6
dst_code |= 0x10;
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I7);
UML_MOV(block, I7, 0);
switch (dst_code)
{
case 16: // G16 reserved
case 17: // G17 reserved
case BCR_REGISTER: // G20 Bus Control Register
case WCR_REGISTER: // G24 Watchdog Compare Register
case 28: // G28 reserved
case 29: // G29 reserved
case 30: // G30 reserved
case 31: // G31 reserved
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
break;
case SP_REGISTER: // G18 Stack Pointer
case UB_REGISTER: // G19 Upper Stack Bound
UML_AND(block, mem(&m_core->global_regs[dst_code]), src, ~uint32_t(3));
break;
case TPR_REGISTER: // G21 Timer Prescaler Register
{
const int skip_compute_tr = compiler.next_label();
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
UML_TEST(block, src, 0x80000000);
UML_JMPc(block, uml::COND_NZ, skip_compute_tr);
UML_CALLC(block, &c_funcs::compute_tr, this);
UML_CALLC(block, &c_funcs::update_timer_prescale, this);
UML_LABEL(block, skip_compute_tr);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
}
break;
case TCR_REGISTER: // G22 Timer Compare Register
{
const int done = compiler.next_label();
UML_MOV(block, I6, mem(&m_core->global_regs[dst_code]));
UML_CMP(block, I6, src);
UML_JMPc(block, uml::COND_E, done);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
UML_LABEL(block, done);
}
break;
case TR_REGISTER: // G23 Timer Register
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
UML_MOV(block, mem(&m_core->tr_base_value), src);
UML_CALLC(block, &c_funcs::total_cycles, this);
UML_DMOV(block, mem(&m_core->tr_base_cycles), mem(&m_core->numcycles));
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
break;
case ISR_REGISTER: // G25 Input Status Register (read-only)
break;
case FCR_REGISTER: // G26 Function Control Register
{
const int skip_adjust_timer = compiler.next_label();
UML_MOV(block, I6, mem(&m_core->global_regs[dst_code]));
UML_XOR(block, I6, I6, src);
UML_TEST(block, I6, 0x80000000);
UML_JMPc(block, uml::COND_Z, skip_adjust_timer);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
UML_LABEL(block, skip_adjust_timer);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
}
break;
case MCR_REGISTER: // G27 Memory Control Register
UML_ROLAND(block, I6, src, 20, 0x7);
UML_LOAD(block, I6, (void *)s_trap_entries, I6, SIZE_DWORD, SCALE_x4);
UML_MOV(block, mem(&m_core->trap_entry), I6);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
break;
default:
throw emu_fatalerror("%s: invalid high global register G%u\n", dst_code);
}
}
void hyperstone_device::generate_load_operand(drcuml_block &block, compiler_state &compiler, reg_bank global, uint32_t code, uml::parameter dst, uml::parameter localidx)
{
// expects frame pointer in I3 if local
// sets localidx if local before setting dst
if (global)
{
UML_MOV(block, dst, mem(&m_core->global_regs[code]));
}
else
{
UML_ADD(block, localidx, I3, code);
UML_AND(block, localidx, localidx, 0x3f);
UML_LOAD(block, dst, (void *)m_core->local_regs, localidx, SIZE_DWORD, SCALE_x4);
}
}
void hyperstone_device::generate_load_src_addsub(drcuml_block &block, compiler_state &compiler, reg_bank global, uint32_t code, uml::parameter dst, uml::parameter localidx, uml::parameter sr)
{
// expects frame pointer in I3 if local
// sets localidx if local before setting dst
if (global)
{
if (code == SR_REGISTER)
UML_AND(block, dst, sr, C_MASK);
else
UML_MOV(block, dst, mem(&m_core->global_regs[code]));
}
else
{
UML_ADD(block, localidx, I3, code);
UML_AND(block, localidx, localidx, 0x3f);
UML_LOAD(block, dst, (void *)m_core->local_regs, localidx, SIZE_DWORD, SCALE_x4);
}
}
uml::parameter hyperstone_device::generate_load_address_ad(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, reg_bank global, uint32_t code, uml::parameter dst, uml::parameter localidx)
{
// expects frame pointer in I3 if local
// sets localidx if local before setting dst
// returns an immediate for SR or constant PC, otherwise returns dst
if (global)
{
if (code == SR_REGISTER)
{
return 0;
}
else if ((code == PC_REGISTER) && ((desc->flags & OPFLAG_IN_DELAY_SLOT) || !compiler.check_delay()))
{
if (!compiler.pc())
UML_EXH(block, *m_exception, TRAPNO_POINTER_ERROR);
return compiler.pc();
}
else
{
UML_MOV(block, dst, mem(&m_core->global_regs[code]));
}
}
else
{
UML_ADD(block, localidx, I3, code);
UML_AND(block, localidx, localidx, 0x3f);
UML_LOAD(block, dst, (void *)m_core->local_regs, localidx, SIZE_DWORD, SCALE_x4);
}
UML_TEST(block, dst, ~uint32_t(0));
UML_EXHc(block, uml::COND_Z, *m_exception, TRAPNO_POINTER_ERROR);
return dst;
}
void hyperstone_device::generate_load_address_ns(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, reg_bank global, uint32_t code, uml::parameter dst, uml::parameter localidx, uint16_t d_code, uint32_t dis)
{
// expects frame pointer in I3 if local
// sets localidx if local before setting dst
generate_load_operand(block, compiler, global, code, dst, localidx);
const int no_exception = compiler.next_label();
UML_TEST(block, dst, ~uint32_t(0));
UML_JMPc(block, uml::COND_NZ, no_exception);
switch (d_code)
{
case 0: // LDBS.N
case 1: // LDBU.N
UML_ADD(block, dst, dst, dis);
break;
case 2: // LDHS.N, LDHU.N
UML_ADD(block, dst, dst, dis & ~uint32_t(1));
break;
case 3: // LDW.N, LDD.N, LDW.S
UML_ADD(block, dst, dst, dis & ~uint32_t(3));
break;
}
if (global)
UML_MOV(block, mem(&m_core->global_regs[code]), dst);
else
UML_STORE(block, (void *)m_core->local_regs, localidx, dst, SIZE_DWORD, SCALE_x4);
UML_EXH(block, *m_exception, TRAPNO_POINTER_ERROR);
UML_LABEL(block, no_exception);
}
void hyperstone_device::generate_load_address_rp(drcuml_block &block, compiler_state &compiler, uint32_t code, uml::parameter dst, uml::parameter localidx, uint32_t dis)
{
// expects frame pointer in I3 if local
// sets I0 to masked address
// sets localidx if local before setting dst
// localidx must not conflict with dst if dis is non-zero
generate_load_operand(block, compiler, LOCAL, code, dst, localidx);
UML_TEST(block, dst, ~uint32_t(0));
if (dis)
{
const int no_exception = compiler.next_label();
UML_JMPc(block, uml::COND_NZ, no_exception);
UML_ADD(block, dst, dst, dis);
UML_STORE(block, (void *)m_core->local_regs, localidx, dst, SIZE_DWORD, SCALE_x4);
UML_EXH(block, *m_exception, TRAPNO_POINTER_ERROR);
UML_LABEL(block, no_exception);
}
else
{
UML_EXHc(block, uml::COND_Z, *m_exception, TRAPNO_POINTER_ERROR);
}
UML_AND(block, I0, dst, ~uint32_t(3));
}
void hyperstone_device::generate_set_dst(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, reg_bank global, uint32_t code, uml::parameter src, uml::parameter localidx, bool calcidx)
{
// expects frame pointer in I3 if local and calcidx is true
// sets localidx if local and calcidx is true before storing src
// localidx is input if local and calcidx is false
// clobbers I4 when setting SR
if (global)
{
generate_set_global_register_low(block, compiler, code, src);
if (code == PC_REGISTER)
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
if (src.is_int_register() && (desc->targetpc == BRANCH_TARGET_DYNAMIC))
{
UML_AND(block, src, src, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), src, desc);
}
else if (src.is_immediate() && (desc->targetpc == BRANCH_TARGET_DYNAMIC))
{
generate_branch(block, compiler, compiler.mode(), src.immediate() & ~uint32_t(1), desc);
}
else
{
generate_branch(block, compiler, compiler.mode(), desc->targetpc, desc);
}
}
}
else
{
if (calcidx)
{
UML_ADD(block, localidx, I3, code);
UML_AND(block, localidx, localidx, 0x3f);
}
UML_STORE(block, (void *)m_core->local_regs, localidx, src, SIZE_DWORD, SCALE_x4);
}
}
void hyperstone_device::generate_update_flags_addsub(drcuml_block &block, compiler_state &compiler, uml::parameter sr)
{
// expects result in I0 and UML flags set by ADD/SUB
// clobbers I1, I4 and I5
UML_SETc(block, uml::COND_V, I4); // I4 = ...V
UML_SETc(block, uml::COND_Z, I5); // I5 = ...Z
UML_SETc(block, uml::COND_C, I1); // I1 = ...C
UML_SHL(block, I4, I4, V_SHIFT); // I4 = V...
UML_OR(block, I1, I1, I4); // I1 = V..C
UML_SHL(block, I4, I5, Z_SHIFT); // I4 = ..Z.
UML_OR(block, I1, I1, I4); // I1 = V.ZC
UML_ROLAND(block, I4, I0, N_SHIFT + 1, N_MASK); // I4 = .N..
UML_OR(block, I1, I1, I4); // I1 = VNZC
UML_ROLINS(block, sr, I1, 0, (V_MASK | N_MASK | Z_MASK | C_MASK));
}
void hyperstone_device::generate_update_flags_addsubc(drcuml_block &block, compiler_state &compiler, uml::parameter sr)
{
// expects result in I0 and UML flags set by ADD/SUB
// clobbers I1, I4 and I5
UML_SETc(block, uml::COND_V, I4); // I4 = ...V
UML_SETc(block, uml::COND_Z, I5); // I5 = ...Z
UML_SETc(block, uml::COND_C, I1); // I1 = ...C
UML_SHL(block, I4, I4, V_SHIFT); // I4 = V...
UML_OR(block, I1, I1, I4); // I1 = V..C
UML_SHL(block, I4, I5, Z_SHIFT); // I4 = ..Z.
UML_OR(block, I1, I1, I4); // I1 = V.ZC
UML_ROLAND(block, I4, I0, N_SHIFT + 1, N_MASK); // I4 = .N..
UML_OR(block, I1, I1, I4); // I1 = VNZC
UML_OR(block, I4, I2, ~Z_MASK); // combine with old Z flag
UML_AND(block, I1, I1, I4);
UML_ROLINS(block, sr, I1, 0, (V_MASK | N_MASK | Z_MASK | C_MASK));
}
void hyperstone_device::generate_update_flags_addsubs(drcuml_block &block, compiler_state &compiler, uml::parameter sr)
{
// expects UML flags set by ADD/SUB
// clobbers I1, I4 and I5
UML_SETc(block, uml::COND_V, I4); // I4 = ...V
UML_SETc(block, uml::COND_S, I1); // I1 = ...S
UML_SETc(block, uml::COND_Z, I5); // I5 = ...Z
UML_SHL(block, I4, I4, V_SHIFT); // I4 = V...
UML_SHL(block, I1, I1, N_SHIFT); // I1 = .N..
UML_OR(block, I1, I1, I4); // I1 = VN..
UML_SHL(block, I4, I5, Z_SHIFT); // I4 = ..Z.
UML_OR(block, I1, I1, I4); // I1 = VNZ.
UML_ROLINS(block, sr, I1, 0, (V_MASK | N_MASK | Z_MASK));
}
void hyperstone_device::generate_update_flags_cmp(drcuml_block &block, compiler_state &compiler, uml::parameter sr)
{
// expects UML flags set by ADD/SUB
// clobbers I0, I1, I3 and I4
UML_SETc(block, uml::COND_V, I0); // I0 = ...V
UML_SETc(block, uml::COND_L, I1); // I1 = ...N
UML_SETc(block, uml::COND_Z, I3); // I3 = ...Z
UML_SETc(block, uml::COND_C, I4); // I4 = ...C
UML_AND(block, sr, sr, ~(V_MASK | N_MASK | Z_MASK | C_MASK));
UML_SHL(block, I0, I0, V_SHIFT); // I0 = V...
UML_SHL(block, I1, I1, N_SHIFT); // I1 = .N..
UML_SHL(block, I3, I3, Z_SHIFT); // I3 = ..Z.
UML_SHL(block, I4, I4, C_SHIFT); // I4 = ...C
UML_OR(block, I0, I0, I1); // I0 = VN..
UML_OR(block, I3, I3, I4); // I1 = ..ZC
UML_OR(block, sr, sr, I0);
UML_OR(block, sr, sr, I3);
}
void hyperstone_device::generate_update_nz(drcuml_block &block, compiler_state &compiler, uml::parameter sr)
{
// expects result in I0 and UML Z flag to be set
// clobbers I1
UML_SETc(block, uml::COND_Z, I1);
UML_SHL(block, I1, I1, Z_SHIFT);
UML_ROLINS(block, I1, I0, N_SHIFT + 1, N_MASK);
UML_OR(block, sr, sr, I1);
}
void hyperstone_device::generate_update_nz_d(drcuml_block &block, compiler_state &compiler, uml::parameter sr)
{
// expects result in I0 and UML Z flag to be set
// assumes Z and N bits in sr have already been cleared
// clobbers I1
UML_SETc(block, uml::COND_Z, I1);
UML_SHL(block, I1, I1, Z_SHIFT);
UML_OR(block, sr, sr, I1);
UML_DROLAND(block, I1, I0, N_SHIFT + 1, N_MASK);
UML_OR(block, sr, sr, I1);
}
template <hyperstone_device::trap_exception_or_int TYPE>
void hyperstone_device::generate_trap_exception_or_int(drcuml_block &block, uml::code_label &label, uml::parameter trapno)
{
// expects cycles in I7 (updated)
// clobbers I0, I1, I2, I3 and I4 after using trapno
const uint32_t set_flags = (TYPE == IS_INT) ? (S_MASK | L_MASK | I_MASK) : (S_MASK | L_MASK);
const uint32_t clear_flags = T_MASK | M_MASK;
const uint32_t update_sr = FP_MASK | FL_MASK | set_flags | clear_flags;
if ((TYPE != IS_INT) && (machine().debug_flags & DEBUG_FLAG_ENABLED))
{
if (!trapno.is_int_register())
{
UML_MOV(block, I0, trapno);
trapno = uml::I0;
}
UML_MOV(block, mem(&m_core->arg0), trapno); // let the debugger know
UML_CALLC(block, &c_funcs::debugger_exception_hook, this);
}
generate_get_trap_addr(block, label, trapno); // I0 = target PC
UML_MOV(block, I4, DRC_SR); // I4 = old SR
UML_MOV(block, I1, I4); // I1 = SR to be updated
UML_ROLAND(block, I3, I4, 32 - FP_SHIFT, 0x7f); // I3 = old FP
UML_ROLAND(block, I2, I4, 32 - FL_SHIFT, 0xf); // I2 = old FL
UML_MOVc(block, uml::COND_Z, I2, 16); // convert FL == 0 to 16
UML_ADD(block, I3, I3, I2); // I3 = updated FP
UML_SHL(block, I2, I3, FP_SHIFT); // I2 = updated FP:...
UML_OR(block, I2, I2, (((TYPE != IS_TRAP) ? 2 : 6) << FL_SHIFT) | set_flags);
UML_ROLINS(block, I1, I2, 0, update_sr); // update SR value
UML_MOV(block, DRC_SR, I1); // store updated SR
UML_AND(block, I3, I3, 0x3f); // save old PC at updated (FP)^
UML_AND(block, I2, DRC_PC, ~uint32_t(1));
UML_ROLINS(block, I2, I4, 32 - S_SHIFT, 1);
UML_STORE(block, (void *)m_core->local_regs, I3, I2, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I3, I3, 1); // save old SR at updated (FP + 1)^
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I4, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I7, I7, mem(&m_core->clock_cycles_2)); // assume exception dispatch takes two cycles
UML_MOV(block, DRC_PC, I0); // branch to exception handler
generate_update_cycles(block);
UML_HASHJMP(block, 1, I0, *m_nocode); // T cleared and S set - mode will always be 1
}
void hyperstone_device::generate_trap_on_overflow(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uml::parameter sr)
{
const int no_exception = compiler.next_label();
UML_TEST(block, sr, V_MASK);
UML_JMPc(block, uml::COND_Z, no_exception);
UML_ROLINS(block, sr, ((desc->length >> 1) << ILC_SHIFT) | P_MASK, 0, ILC_MASK | P_MASK);
UML_MOV(block, DRC_SR, sr);
UML_EXH(block, *m_exception, TRAPNO_RANGE_ERROR);
UML_LABEL(block, no_exception);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal, typename T>
inline void hyperstone_device::generate_logic_op(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, T &&body)
{
// body takes operands in I0 and I1 and should update I0 and set Z flag
// body must not clobber I2 or I3
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I1, uml::I1);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
body();
UML_SETc(block, uml::COND_Z, I1);
UML_ROLINS(block, I2, I1, Z_SHIFT, Z_MASK);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
template <hyperstone_device::reg_bank DstGlobal, typename T>
inline void hyperstone_device::generate_logic_op_imm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint32_t dst_code, T &&body)
{
// clobbers I0, I1 and I3
// body should update I0 and set Z flag
// body must not clobber I2 or I3
UML_MOV(block, I2, DRC_SR);
if (!DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
body();
UML_SETc(block, uml::COND_Z, I1);
UML_ROLINS(block, I2, I1, Z_SHIFT, Z_MASK);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
void hyperstone_device::generate_software(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_6));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t srcf_code = src_code + 1;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f); // I3 = FP
UML_ADD(block, I2, I3, src_code);
UML_AND(block, I4, I2, 0x3f);
UML_LOAD(block, I0, (void *)m_core->local_regs, I4, SIZE_DWORD, SCALE_x4); // I0 = sreg
UML_ADD(block, I2, I3, srcf_code);
UML_AND(block, I4, I2, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I4, SIZE_DWORD, SCALE_x4); // I1 = sregf
UML_ROLINS(block, DRC_SR, 1, ILC_SHIFT, ILC_MASK);
uint32_t num = op >> 8;
int mem3 = compiler.next_label();
int have_code_addr = compiler.next_label();
UML_MOV(block, I4, mem(&m_core->trap_entry));
UML_CMP(block, I4, 0xffffff00);
UML_JMPc(block, uml::COND_E, mem3);
UML_OR(block, I5, I4, (0x10c | ((0xcf - num) << 4)));
UML_JMP(block, have_code_addr);
UML_LABEL(block, mem3);
UML_SUB(block, I5, I4, 0x100);
UML_OR(block, I5, I5, ((num & 0xf) << 4)); // I5 = addr
UML_LABEL(block, have_code_addr);
UML_ROLAND(block, I2, DRC_SR, 32 - FL_SHIFT, 0xf);
UML_MOVc(block, uml::COND_Z, I2, 16);
UML_ADD(block, I4, I2, I3); // I4 = reg
UML_AND(block, I2, mem(&SP), 0xffffff00);
UML_ADD(block, I6, I2, 0x100); // I6 = (SP & ~0xff) + 0x100
UML_ADD(block, I2, I3, dst_code);
UML_AND(block, I2, I2, 0x3f);
UML_SHL(block, I2, I2, 2); // I2 = (((fp + DST_CODE) & 0x3f) << 2)
UML_ADD(block, I6, I6, I2); // I6 = (SP & ~0xff) + 0x100 + (((fp + DST_CODE) & 0x3f) << 2)
UML_AND(block, I2, I4, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I6, SIZE_DWORD, SCALE_x4); // m_core->local_regs[(reg + 0) & 0x3f] = stack_of_dst;
UML_ADD(block, I6, I2, 1);
UML_AND(block, I2, I6, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I0, SIZE_DWORD, SCALE_x4); // m_core->local_regs[(reg + 1) & 0x3f] = sreg;
UML_ADD(block, I6, I2, 1);
UML_AND(block, I2, I6, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I1, SIZE_DWORD, SCALE_x4); // m_core->local_regs[(reg + 2) & 0x3f] = sregf;
UML_AND(block, I0, DRC_PC, ~uint32_t(1));
UML_ROLINS(block, I0, DRC_SR, 32 - S_SHIFT, 1);
UML_ADD(block, I6, I2, 1);
UML_AND(block, I2, I6, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I0, SIZE_DWORD, SCALE_x4); // m_core->local_regs[(reg + 3) & 0x3f] = (PC & ~1) | GET_S;
UML_ADD(block, I6, I2, 1);
UML_AND(block, I2, I6, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, DRC_SR, SIZE_DWORD, SCALE_x4); // m_core->local_regs[(reg + 4) & 0x3f] = oldSR;
UML_MOV(block, DRC_PC, I5); // PC = addr
UML_MOV(block, I0, DRC_SR);
UML_ROLINS(block, I0, (6 << FL_SHIFT) | L_MASK, 0, FL_MASK | T_MASK | L_MASK | M_MASK); // FL = 6, T = 0, L = 1, M = 0
UML_ROLINS(block, I0, I4, FP_SHIFT, FP_MASK); // SET_FP(reg)
UML_MOV(block, DRC_SR, I0);
generate_branch(block, compiler, compiler.mode() & 0x1, uml::I5, desc); // T cleared - only keep S in bit zero of mode
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_chk(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
// checking a register other than PC against itself is a NOP
if ((DstGlobal == SrcGlobal) && (src_code == dst_code) && (!DstGlobal || (src_code > SR_REGISTER)))
return;
// checking PC against itself will always trap
const bool unconditional = DstGlobal && SrcGlobal && (src_code == PC_REGISTER) && (dst_code == PC_REGISTER);
UML_MOV(block, I2, DRC_SR);
if (!DstGlobal || !SrcGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I0);
int done;
if (!unconditional)
{
done = compiler.next_label();
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
{
UML_TEST(block, I0, ~uint32_t(0));
UML_JMPc(block, uml::COND_NZ, done);
}
else
{
UML_MOV(block, I1, mem(&m_core->global_regs[src_code]));
UML_CMP(block, I0, I1);
if (src_code == PC_REGISTER)
UML_JMPc(block, uml::COND_B, done);
else
UML_JMPc(block, uml::COND_BE, done);
}
}
else
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
UML_CMP(block, I0, I1);
UML_JMPc(block, uml::COND_BE, done);
}
}
UML_ROLINS(block, I2, ((desc->length >> 1) << ILC_SHIFT) | P_MASK, 0, ILC_MASK | P_MASK);
UML_MOV(block, DRC_SR, I2);
UML_EXH(block, *m_exception, TRAPNO_RANGE_ERROR);
if (!unconditional)
UML_LABEL(block, done);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_movd(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t srcf_code = src_code + 1;
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t dstf_code = dst_code + 1;
if (DstGlobal && (dst_code == PC_REGISTER))
{
if (SrcGlobal && (src_code < 2))
{
osd_printf_error("Denoted PC or SR in RET instruction. PC = %08X\n", desc->pc);
return;
}
UML_MOV(block, I3, DRC_SR);
if (SrcGlobal)
{
UML_MOV(block, I0, mem(&m_core->global_regs[src_code]));
UML_MOV(block, I2, mem(&m_core->global_regs[srcf_code]));
}
else
{
UML_ROLAND(block, I2, I3, 32 - FP_SHIFT, 0x7f);
UML_ADD(block, I0, I2, src_code);
UML_AND(block, I0, I0, 0x3f);
UML_LOAD(block, I0, (void *)m_core->local_regs, I0, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I2, I2, srcf_code);
UML_AND(block, I2, I2, 0x3f);
UML_LOAD(block, I2, (void *)m_core->local_regs, I2, SIZE_DWORD, SCALE_x4);
}
UML_AND(block, I2, I2, ~(ILC_MASK | S_MASK)); // clear ILC, restore S from bit zero of Rs
UML_ROLINS(block, I2, I0, S_SHIFT, S_MASK);
UML_MOV(block, DRC_SR, I2);
UML_AND(block, I0, I0, ~uint32_t(1));
UML_MOV(block, DRC_PC, I0);
if (compiler.user_mode())
{
// privilege exception on setting S or L
UML_XOR(block, I3, I3, ~uint32_t(0));
UML_AND(block, I3, I3, S_MASK | L_MASK);
UML_TEST(block, I3, I2);
UML_EXHc(block, uml::COND_NZ, *m_exception, TRAPNO_PRIVILEGE_ERROR);
}
else
{
// privilege exception on setting L while clearing S
UML_XOR(block, I3, I3, ~uint32_t(0)); // I3(15) = !L
UML_AND(block, I3, I3, I2); // I3(15) = !L && L'
UML_XOR(block, I3, I3, ~uint32_t(0)); // I3(15) = !(!L && L') = L || !L'
UML_SHL(block, I3, I3, S_SHIFT - L_SHIFT); // I3(18) = L || !L'
UML_OR(block, I3, I3, I2); // I3(18) = L || !L' || S'
UML_TEST(block, I3, S_MASK);
UML_EXHc(block, uml::COND_Z, *m_exception, TRAPNO_PRIVILEGE_ERROR);
}
const int pop_next = compiler.next_label();
const int done_ret = compiler.next_label();
UML_MOV(block, I0, mem(&SP)); // I0 = SP
UML_ROLAND(block, I1, I0, 30, 0x7f); // I3 = FP - SP(8..2)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
UML_SUB(block, I3, I3, I1);
UML_SHL(block, I3, I3, 32 - 7); // sign-extend 7-bit number
UML_SAR(block, I3, I3, 32 - 7);
UML_JMPc(block, uml::COND_NS, done_ret); // nothing to pull if not negative
UML_LABEL(block, pop_next);
UML_SUB(block, I0, I0, 4); // pull a word
UML_CALLH(block, *m_mem_read32);
UML_AND(block, I4, I0, 0x3f << 2);
UML_STORE(block, (void *)m_core->local_regs, I4, I1, SIZE_DWORD, SCALE_x1);
UML_ADD(block, I3, I3, 1); // increment counter
UML_JMPc(block, uml::COND_S, pop_next); // done if not negative
UML_MOV(block, mem(&SP), I0); // SP = I0
UML_LABEL(block, done_ret);
generate_branch(block, compiler, BRANCH_TARGET_DYNAMIC, desc->targetpc, nullptr); // don't pass desc - must not update ILC and P
return;
}
else if (SrcGlobal && (src_code == SR_REGISTER)) // Rd doesn't denote PC and Rs denotes SR
{
UML_OR(block, DRC_SR, DRC_SR, Z_MASK);
UML_AND(block, DRC_SR, DRC_SR, ~N_MASK);
if (DstGlobal)
{
generate_set_global_register_low(block, compiler, dst_code, 0);
UML_MOV(block, I5, 0);
generate_set_global_register(block, compiler, desc, dstf_code);
}
else
{
UML_ROLAND(block, I0, DRC_SR, 32 - FP_SHIFT, 0x7f);
UML_ADD(block, I0, I0, dst_code);
UML_AND(block, I0, I0, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I0, 0, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I0, I0, 1);
UML_AND(block, I0, I0, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I0, 0, SIZE_DWORD, SCALE_x4);
}
}
else // Rd doesn't denote PC and Rs doesn't denote SR
{
if (!SrcGlobal || !DstGlobal)
{
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
}
if (SrcGlobal)
{
UML_MOV(block, I0, mem(&m_core->global_regs[src_code]));
UML_MOV(block, I1, mem(&m_core->global_regs[srcf_code]));
}
else
{
UML_ADD(block, I0, I3, src_code);
UML_AND(block, I0, I0, 0x3f);
UML_LOAD(block, I0, (void *)m_core->local_regs, I0, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I1, I3, srcf_code);
UML_AND(block, I1, I1, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I1, SIZE_DWORD, SCALE_x4);
}
UML_AND(block, DRC_SR, DRC_SR, ~(Z_MASK | N_MASK));
UML_OR(block, I2, I0, I1);
UML_TEST(block, I2, ~0);
UML_SETc(block, uml::COND_Z, I2);
UML_ROLINS(block, DRC_SR, I2, Z_SHIFT, Z_MASK);
UML_TEST(block, I0, 0x80000000);
UML_SETc(block, uml::COND_NZ, I2);
UML_ROLINS(block, DRC_SR, I2, N_SHIFT, N_MASK);
if (DstGlobal)
{
generate_set_global_register_low(block, compiler, dst_code, uml::I0);
UML_MOV(block, I5, I1);
generate_set_global_register(block, compiler, desc, dstf_code);
}
else
{
UML_ADD(block, I2, I3, dst_code);
UML_AND(block, I2, I2, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I0, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I2, I3, dstf_code);
UML_AND(block, I2, I2, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I1, SIZE_DWORD, SCALE_x4);
}
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal, hyperstone_device::sign_mode SIGNED>
void hyperstone_device::generate_divsu(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_36));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t dstf_code = dst_code + 1;
const uint32_t src_code = op & 0xf;
if ((SrcGlobal == DstGlobal && (src_code == dst_code || src_code == dstf_code)) || (SrcGlobal && src_code < 2))
{
osd_printf_error("Denoted the same register code or PC/SR as source in generate_divsu. PC = %08X\n", desc->pc);
return;
}
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I0, uml::I0);
if (DstGlobal)
{
UML_MOV(block, I1, mem(&m_core->global_regs[dst_code]));
UML_MOV(block, I2, mem(&m_core->global_regs[dstf_code]));
}
else
{
UML_ADD(block, I2, I3, dst_code);
UML_AND(block, I5, I2, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I5, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I4, I3, dstf_code);
UML_AND(block, I6, I4, 0x3f);
UML_LOAD(block, I2, (void *)m_core->local_regs, I6, SIZE_DWORD, SCALE_x4);
}
UML_DSHL(block, I1, I1, 32);
UML_DOR(block, I1, I1, I2);
int no_result = compiler.next_label();
int done = compiler.next_label();
UML_TEST(block, I0, ~0);
UML_JMPc(block, uml::COND_Z, no_result);
if (SIGNED)
{
UML_DTEST(block, I1, 0x8000000000000000LL);
UML_JMPc(block, uml::COND_NZ, no_result);
UML_DSEXT(block, I0, I0, SIZE_DWORD);
}
if (SIGNED)
UML_DDIVS(block, I2, I4, I1, I0);
else
UML_DDIVU(block, I2, I4, I1, I0);
UML_AND(block, I3, DRC_SR, ~(V_MASK | Z_MASK | N_MASK));
UML_TEST(block, I2, ~uint32_t(0));
UML_SETc(block, uml::COND_Z, I0);
UML_SHL(block, I0, I0, Z_SHIFT);
UML_ROLINS(block, I0, I2, N_SHIFT + 1, N_MASK);
UML_OR(block, DRC_SR, I3, I0);
if (DstGlobal)
{
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I4);
UML_MOV(block, mem(&m_core->global_regs[dstf_code]), I2);
}
else
{
UML_STORE(block, (void *)m_core->local_regs, I5, I4, SIZE_DWORD, SCALE_x4);
UML_STORE(block, (void *)m_core->local_regs, I6, I2, SIZE_DWORD, SCALE_x4);
}
UML_JMP(block, done);
UML_LABEL(block, no_result);
UML_ROLINS(block, DRC_SR, ((desc->length >> 1) << ILC_SHIFT) | P_MASK | V_MASK, 0, ILC_MASK | P_MASK | V_MASK);
UML_EXH(block, *m_exception, TRAPNO_RANGE_ERROR);
UML_LABEL(block, done);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_xm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
const uint32_t next = m_pr16(desc->pc + 2);
const uint8_t sub_type = (next & 0x7000) >> 12;
uint32_t extra_u = next & 0xfff;
if (next & 0x8000)
extra_u = ((extra_u & 0xfff) << 16) | m_pr16(desc->pc + 4);
if ((SrcGlobal && (src_code == SR_REGISTER)) || (DstGlobal && (dst_code < 2)))
return;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I1, uml::I1);
UML_SHL(block, I0, I1, sub_type & 3);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, true);
if (sub_type < 4)
{
const int done = compiler.next_label();
UML_CMP(block, I1, extra_u);
if (SrcGlobal && (src_code == PC_REGISTER))
UML_JMPc(block, uml::COND_B, done);
else
UML_JMPc(block, uml::COND_BE, done);
UML_ROLINS(block, I2, ((desc->length >> 1) << ILC_SHIFT) | P_MASK, 0, ILC_MASK | P_MASK);
UML_MOV(block, DRC_SR, I2);
UML_EXH(block, *m_exception, TRAPNO_RANGE_ERROR);
UML_LABEL(block, done);
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_mask(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src = generate_get_const(desc);
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I0, uml::I0);
UML_AND(block, I0, I0, src);
UML_SETc(block, uml::COND_Z, I1);
UML_ROLINS(block, I2, I1, Z_SHIFT, Z_MASK);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, true);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_sum(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src = generate_get_const(desc);
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal && (src_code == PC_REGISTER) && ((desc->flags & OPFLAG_IN_DELAY_SLOT) || !compiler.check_delay()))
{
const uint64_t result = uint64_t(compiler.pc()) + src;
const uint32_t flags =
(BIT(result, 32) << C_SHIFT) |
(!uint32_t(result) ? Z_MASK : 0) |
(BIT(result, 31) << N_SHIFT) |
(BIT((compiler.pc() ^ result) & (src ^ result), 31) << V_SHIFT);
UML_ROLINS(block, I2, flags, 0, V_MASK | N_MASK | Z_MASK | C_MASK);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uint32_t(result), uml::I3, true);
}
else
{
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I0, uml::I0);
UML_ADD(block, I0, I0, src);
generate_update_flags_addsub(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, true);
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_sums(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src = generate_get_const(desc);
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I0, uml::I0);
UML_ADD(block, I0, I0, src);
generate_update_flags_addsubs(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, true);
generate_trap_on_overflow(block, compiler, desc, uml::I2);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_cmp(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_src_addsub(block, compiler, SrcGlobal, src_code, uml::I1, uml::I1, uml::I2);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_CMP(block, I0, I1);
generate_update_flags_cmp(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_mov(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_AND(block, I2, DRC_SR, ~(Z_MASK | N_MASK));
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
if (DstGlobal && compiler.user_mode())
{
UML_TEST(block, I2, H_MASK);
UML_EXHc(block, uml::COND_NZ, *m_exception, TRAPNO_PRIVILEGE_ERROR);
}
if (SrcGlobal)
{
if (!DstGlobal || compiler.supervisor_mode())
{
const int highglobal = compiler.next_label();
const int done = compiler.next_label();
UML_TEST(block, I2, H_MASK);
UML_JMPc(block, uml::COND_NZ, highglobal);
UML_MOV(block, I0, mem(&m_core->global_regs[src_code]));
UML_JMP(block, done);
UML_LABEL(block, highglobal);
generate_get_global_register_high(block, compiler, src_code, uml::I0);
UML_LABEL(block, done);
}
else
{
UML_MOV(block, I0, mem(&m_core->global_regs[src_code]));
}
}
else if (DstGlobal || (src_code == dst_code))
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I0, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
else
{
UML_ADD(block, I0, I3, src_code);
UML_AND(block, I0, I0, 0x3f);
UML_LOAD(block, I0, (void *)m_core->local_regs, I0, SIZE_DWORD, SCALE_x4);
}
UML_TEST(block, I0, ~uint32_t(0));
generate_update_nz(block, compiler, uml::I2);
if (DstGlobal)
{
if (compiler.supervisor_mode())
{
const int highglobal = compiler.next_label();
const int done = compiler.next_label();
UML_TEST(block, I2, H_MASK);
UML_JMPc(block, uml::COND_NZ, highglobal);
UML_MOV(block, DRC_SR, I2);
generate_set_global_register_low(block, compiler, dst_code, uml::I0);
if (dst_code == PC_REGISTER)
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
UML_AND(block, I0, I0, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I0, desc);
}
else
{
UML_JMP(block, done);
}
UML_LABEL(block, highglobal);
UML_AND(block, I2, I2, ~H_MASK);
UML_MOV(block, DRC_SR, I2);
generate_set_global_register_high(block, compiler, dst_code, uml::I0);
UML_LABEL(block, done);
}
else
{
UML_MOV(block, DRC_SR, I2);
generate_set_global_register_low(block, compiler, dst_code, uml::I0);
if (dst_code == PC_REGISTER)
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
UML_AND(block, I0, I0, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I0, desc);
}
}
}
else
{
UML_AND(block, I2, I2, ~H_MASK);
UML_MOV(block, DRC_SR, I2);
if (SrcGlobal || (src_code != dst_code))
{
UML_ADD(block, I3, I3, dst_code);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I0, SIZE_DWORD, SCALE_x4);
}
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_add(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
if ((desc->flags & OPFLAG_IN_DELAY_SLOT) || !compiler.check_delay())
{
const bool srcpc = SrcGlobal && (src_code == PC_REGISTER);
const bool dstpc = DstGlobal && (dst_code == PC_REGISTER);
if (srcpc && dstpc)
{
// degenerate case - effectively left-shift PC
const uint32_t result = compiler.pc() << 1;
const uint32_t flags =
(BIT(compiler.pc(), 31) << C_SHIFT) |
(!result ? Z_MASK : 0) |
(BIT(result, 31) << N_SHIFT) |
(BIT((compiler.pc() ^ result), 31) << V_SHIFT);
UML_ROLINS(block, I2, flags, 0, M_MASK | V_MASK | N_MASK | Z_MASK | C_MASK);
UML_MOV(block, DRC_SR, I2);
UML_MOV(block, DRC_PC, result);
generate_branch(block, compiler, compiler.mode(), result, desc);
return;
}
else if (srcpc)
{
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_ADD(block, I0, I0, compiler.pc());
generate_update_flags_addsub(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
return;
}
else if (dstpc)
{
generate_load_src_addsub(block, compiler, SrcGlobal, src_code, uml::I0, uml::I3, uml::I2);
UML_ADD(block, I0, I0, compiler.pc());
generate_update_flags_addsub(block, compiler, uml::I2);
UML_AND(block, I2, I2, ~M_MASK);
UML_MOV(block, DRC_SR, I2);
UML_AND(block, I0, I0, ~uint32_t(1));
UML_MOV(block, DRC_PC, I0);
generate_branch(block, compiler, compiler.mode(), uml::I0, desc);
return;
}
}
generate_load_src_addsub(block, compiler, SrcGlobal, src_code, uml::I1, uml::I1, uml::I2);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_ADD(block, I0, I0, I1);
generate_update_flags_addsub(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_adds(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_src_addsub(block, compiler, SrcGlobal, src_code, uml::I1, uml::I1, uml::I2);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_ADD(block, I0, I0, I1);
generate_update_flags_addsubs(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
generate_trap_on_overflow(block, compiler, desc, uml::I2);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_cmpb(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I1, uml::I1);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_TEST(block, I0, I1);
UML_SETc(block, uml::COND_Z, I0);
UML_ROLINS(block, DRC_SR, I0, Z_SHIFT, Z_MASK);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_subc(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_src_addsub(block, compiler, SrcGlobal,src_code, uml::I1, uml::I1, uml::I2);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
if (!SrcGlobal || (src_code != SR_REGISTER))
{
UML_SHR(block, I4, I2, C_SHIFT + 1); // set up carry in, result unused
UML_SUBB(block, I0, I0, I1);
}
else
{
UML_SUB(block, I0, I0, I1);
}
generate_update_flags_addsubc(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_sub(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_src_addsub(block, compiler, SrcGlobal, src_code, uml::I1, uml::I1, uml::I2);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_SUB(block, I0, I0, I1);
generate_update_flags_addsub(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_subs(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_src_addsub(block, compiler, SrcGlobal, src_code, uml::I1, uml::I1, uml::I2);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_SUB(block, I0, I0, I1);
generate_update_flags_addsubs(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
generate_trap_on_overflow(block, compiler, desc, uml::I2);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_addc(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_src_addsub(block, compiler, SrcGlobal,src_code, uml::I1, uml::I1, uml::I2);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
if (!SrcGlobal || (src_code != SR_REGISTER))
{
UML_SHR(block, I4, I2, C_SHIFT + 1); // set up carry in, result unused
UML_ADDC(block, I0, I0, I1);
}
else
{
UML_ADD(block, I0, I0, I1);
}
generate_update_flags_addsubc(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_neg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_src_addsub(block, compiler, SrcGlobal, src_code, uml::I0, uml::I0, uml::I2);
UML_SUB(block, I0, 0, I0);
generate_update_flags_addsub(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, true);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_negs(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_src_addsub(block, compiler, SrcGlobal, src_code, uml::I0, uml::I0, uml::I2);
UML_SUB(block, I0, 0, I0);
generate_update_flags_addsubs(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, true);
if (!SrcGlobal || (src_code != SR_REGISTER)) // negating carry cannot result in overflow
generate_trap_on_overflow(block, compiler, desc, uml::I2);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_and(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
generate_logic_op<DstGlobal, SrcGlobal>(
block,
compiler,
desc,
[&block] () { UML_AND(block, I0, I0, I1); });
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_andn(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
generate_logic_op<DstGlobal, SrcGlobal>(
block,
compiler,
desc,
[&block] () { UML_XOR(block, I1, I1, ~uint32_t(0)); UML_AND(block, I0, I0, I1); });
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_or(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
generate_logic_op<DstGlobal, SrcGlobal>(
block,
compiler,
desc,
[&block] () { UML_OR(block, I0, I0, I1); });
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_xor(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
generate_logic_op<DstGlobal, SrcGlobal>(
block,
compiler,
desc,
[&block] () { UML_XOR(block, I0, I0, I1); });
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_not(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_MOV(block, I2, DRC_SR);
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I0, uml::I0);
UML_XOR(block, I0, I0, ~uint32_t(0));
UML_SETc(block, uml::COND_Z, I1);
UML_ROLINS(block, I2, I1, Z_SHIFT, Z_MASK);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, true);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::imm_size ImmLong>
void hyperstone_device::generate_cmpi(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
uint32_t src;
if (ImmLong)
src = generate_get_immediate_s(desc);
else
src = op & 0x0f;
UML_MOV(block, I2, DRC_SR);
if (!DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I0);
UML_CMP(block, I0, src);
generate_update_flags_cmp(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::imm_size ImmLong>
void hyperstone_device::generate_movi(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
uint32_t src;
if (ImmLong)
src = generate_get_immediate_s(desc);
else
src = op & 0x0f;
UML_AND(block, I2, DRC_SR, ~(Z_MASK | N_MASK));
if (DstGlobal && compiler.user_mode())
{
UML_TEST(block, I2, H_MASK);
UML_EXHc(block, uml::COND_NZ, *m_exception, TRAPNO_PRIVILEGE_ERROR);
}
if (!src)
UML_OR(block, I2, I2, Z_MASK);
else if (src & 0x80000000)
UML_OR(block, I2, I2, N_MASK);
#if MISSIONCRAFT_FLAGS
UML_AND(block, I2, I2, ~V_MASK);
#endif
if (DstGlobal)
{
if (compiler.supervisor_mode())
{
const int highglobal = compiler.next_label();
const int done = compiler.next_label();
UML_TEST(block, I2, H_MASK);
UML_JMPc(block, uml::COND_NZ, highglobal);
UML_MOV(block, DRC_SR, I2);
generate_set_global_register_low(block, compiler, dst_code, src);
if (dst_code == PC_REGISTER)
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
generate_branch(block, compiler, compiler.mode(), src & ~uint32_t(1), desc);
}
else
{
UML_JMP(block, done);
}
UML_LABEL(block, highglobal);
UML_AND(block, I2, I2, ~H_MASK);
UML_MOV(block, DRC_SR, I2);
generate_set_global_register_high(block, compiler, dst_code, src);
UML_LABEL(block, done);
}
else
{
UML_MOV(block, DRC_SR, I2);
generate_set_global_register_low(block, compiler, dst_code, src);
if (dst_code == PC_REGISTER)
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
generate_branch(block, compiler, compiler.mode(), src & ~uint32_t(1), desc);
}
}
}
else
{
UML_AND(block, I2, I2, ~H_MASK);
UML_MOV(block, DRC_SR, I2);
UML_ROLAND(block, I2, I2, 32 - FP_SHIFT, 0x7f);
UML_ADD(block, I2, I2, dst_code);
UML_AND(block, I2, I2, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, src, SIZE_DWORD, SCALE_x4);
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::imm_size ImmLong>
void hyperstone_device::generate_addi(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const bool roundeven = !(op & 0x10f);
uint32_t src;
if (ImmLong)
src = generate_get_immediate_s(desc);
else
src = op & 0x0f;
UML_MOV(block, I2, DRC_SR);
if (!DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
if (DstGlobal && (dst_code == PC_REGISTER) && ((desc->flags & OPFLAG_IN_DELAY_SLOT) || !compiler.check_delay()))
{
uint64_t result;
uint32_t flags;
if (roundeven)
{
// PC is always even so rounding to even can't cause carry or overflow
result = compiler.pc();
flags = (!uint32_t(result) ? Z_MASK : 0) | (BIT(result, 31) << N_SHIFT);
}
else
{
result = uint64_t(compiler.pc()) + src;
flags =
(BIT(result, 32) << C_SHIFT) |
(!uint32_t(result) ? Z_MASK : 0) |
(BIT(result, 31) << N_SHIFT) |
(BIT((compiler.pc() ^ result) & (src ^ result), 31) << V_SHIFT);
}
UML_ROLINS(block, I2, flags, 0, M_MASK | V_MASK | N_MASK | Z_MASK | C_MASK);
UML_MOV(block, DRC_SR, I2);
result = uint32_t(result) & uint32_t(1);
UML_MOV(block, DRC_PC, result);
generate_branch(block, compiler, compiler.mode(), result, desc);
}
else
{
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
uml::parameter srcp = roundeven ? uml::I1 : src;
if (roundeven)
{
UML_AND(block, I1, I0, 1); // Rd(0)
UML_AND(block, I1, I1, I2); // & C
UML_TEST(block, I2, Z_MASK);
UML_MOVc(block, uml::COND_NZ, I1, 0); // & ~Z
}
UML_ADD(block, I0, I0, srcp);
generate_update_flags_addsub(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::imm_size ImmLong>
void hyperstone_device::generate_addsi(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
osd_printf_error("Unimplemented: generate_addsi (%08x)\n", desc->pc);
fflush(stdout);
fatalerror(" ");
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::imm_size ImmLong>
void hyperstone_device::generate_cmpbi(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
if (!DstGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
const uint32_t n = ((op & 0x100) >> 4) | (op & 0x0f);
if (n)
{
uint32_t src;
if (n == 31)
src = 0x7fffffff;
else if (ImmLong)
src = generate_get_immediate_s(desc);
else
src = op & 0xf;
UML_TEST(block, I0, src);
UML_SETc(block, uml::COND_Z, I1);
UML_ROLINS(block, DRC_SR, I1, Z_SHIFT, Z_MASK);
}
else
{
const int or_mask = compiler.next_label();
const int done = compiler.next_label();
UML_TEST(block, I0, 0xff000000);
UML_JMPc(block, uml::COND_Z, or_mask);
UML_TEST(block, I0, 0x00ff0000);
UML_JMPc(block, uml::COND_Z, or_mask);
UML_TEST(block, I0, 0x0000ff00);
UML_JMPc(block, uml::COND_Z, or_mask);
UML_TEST(block, I0, 0x000000ff);
UML_JMPc(block, uml::COND_Z, or_mask);
UML_AND(block, DRC_SR, DRC_SR, ~Z_MASK);
UML_JMP(block, done);
UML_LABEL(block, or_mask);
UML_OR(block, DRC_SR, DRC_SR, Z_MASK);
UML_LABEL(block, done);
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::imm_size ImmLong>
void hyperstone_device::generate_andni(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
uint32_t src;
if (DRC_N_OP_MASK == 0x10f)
src = 0x7fffffff;
else if (ImmLong)
src = generate_get_immediate_s(desc);
else
src = op & 0x0f;
src = ~src;
generate_logic_op_imm<DstGlobal>(
block,
compiler,
desc,
(op & 0xf0) >> 4,
[&block, src] () { UML_AND(block, I0, I0, src); });
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::imm_size ImmLong>
void hyperstone_device::generate_ori(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
uint32_t src;
if (ImmLong)
src = generate_get_immediate_s(desc);
else
src = op & 0x0f;
generate_logic_op_imm<DstGlobal>(
block,
compiler,
desc,
(op & 0xf0) >> 4,
[&block, src] () { UML_OR(block, I0, I0, src); });
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::imm_size ImmLong>
void hyperstone_device::generate_xori(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
uint32_t src;
if (ImmLong)
src = generate_get_immediate_s(desc);
else
src = op & 0x0f;
generate_logic_op_imm<DstGlobal>(
block,
compiler,
desc,
(op & 0xf0) >> 4,
[&block, src] () { UML_XOR(block, I0, I0, src); });
}
template <hyperstone_device::shift_type HiN>
void hyperstone_device::generate_shrdi(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t n = HiN ? DRC_HI_N_VALUE : DRC_LO_N_VALUE;
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I1, uml::I4);
generate_load_operand(block, compiler, LOCAL, dst_code + 1, uml::I0, uml::I3);
UML_DSHL(block, I1, I1, 32);
UML_DOR(block, I0, I0, I1);
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
if (n)
{
UML_DROLAND(block, I1, I0, 64 - C_SHIFT + 1 - n, C_MASK);
UML_OR(block, I2, I2, I1);
}
UML_DSHR(block, I0, I0, n);
generate_update_nz_d(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
UML_DSHR(block, I1, I0, 32);
UML_STORE(block, (void *)m_core->local_regs, I4, I1, SIZE_DWORD, SCALE_x4);
UML_STORE(block, (void *)m_core->local_regs, I3, I0, SIZE_DWORD, SCALE_x4);
}
void hyperstone_device::generate_shrd(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
if ((src_code == dst_code) || (src_code == (dst_code + 1)))
{
return; // undefined if Ls overlaps Ld or Ldf
}
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I1, uml::I4);
generate_load_operand(block, compiler, LOCAL, dst_code + 1, uml::I0, uml::I5);
UML_DSHL(block, I1, I1, 32);
UML_DOR(block, I0, I0, I1);
generate_load_operand(block, compiler, LOCAL, src_code, uml::I1, uml::I3);
const int no_shift = compiler.next_label();
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
UML_AND(block, I1, I1, 0x1f);
UML_JMPc(block, uml::COND_Z, no_shift);
UML_SUB(block, I3, 64 - C_SHIFT + 1, I1);
UML_DROLAND(block, I3, I0, I3, C_MASK);
UML_OR(block, I2, I2, I3);
UML_LABEL(block, no_shift);
UML_DSHR(block, I0, I0, I1);
generate_update_nz_d(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
UML_DSHR(block, I1, I0, 32);
UML_STORE(block, (void *)m_core->local_regs, I4, I1, SIZE_DWORD, SCALE_x4);
UML_STORE(block, (void *)m_core->local_regs, I5, I0, SIZE_DWORD, SCALE_x4);
}
void hyperstone_device::generate_shr(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, src_code, uml::I1, uml::I1);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I0, uml::I3);
const int no_shift = compiler.next_label();
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
UML_AND(block, I1, I1, 0x1f);
UML_JMPc(block, uml::COND_Z, no_shift);
UML_SUB(block, I4, 32 - C_SHIFT + 1, I1);
UML_ROLAND(block, I4, I0, I4, C_MASK);
UML_OR(block, I2, I2, I4);
UML_LABEL(block, no_shift);
UML_SHR(block, I0, I0, I1);
generate_update_nz(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
UML_STORE(block, (void *)m_core->local_regs, I3, I0, SIZE_DWORD, SCALE_x4);
}
template <hyperstone_device::shift_type HiN, hyperstone_device::reg_bank DstGlobal>
void hyperstone_device::generate_shri(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t n = HiN ? DRC_HI_N_VALUE : DRC_LO_N_VALUE;
UML_MOV(block, I2, DRC_SR);
if (!DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
if (n)
{
UML_ROLAND(block, I4, I0, 32 - C_SHIFT + 1 - n, C_MASK);
UML_OR(block, I2, I2, I4);
}
UML_SHR(block, I0, I0, n);
generate_update_nz(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
template <hyperstone_device::shift_type HiN>
void hyperstone_device::generate_sardi(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t n = HiN ? DRC_HI_N_VALUE : DRC_LO_N_VALUE;
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I1, uml::I4);
generate_load_operand(block, compiler, LOCAL, dst_code + 1, uml::I0, uml::I3);
UML_DSHL(block, I1, I1, 32);
UML_DOR(block, I0, I0, I1);
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
if (n)
{
UML_DROLAND(block, I1, I0, 64 - C_SHIFT + 1 - n, C_MASK);
UML_OR(block, I2, I2, I1);
}
UML_DSAR(block, I0, I0, n);
generate_update_nz_d(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
UML_DSHR(block, I1, I0, 32);
UML_STORE(block, (void *)m_core->local_regs, I4, I1, SIZE_DWORD, SCALE_x4);
UML_STORE(block, (void *)m_core->local_regs, I3, I0, SIZE_DWORD, SCALE_x4);
}
void hyperstone_device::generate_sard(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
if ((src_code == dst_code) || (src_code == (dst_code + 1)))
{
return; // undefined if Ls overlaps Ld or Ldf
}
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I1, uml::I4);
generate_load_operand(block, compiler, LOCAL, dst_code + 1, uml::I0, uml::I5);
UML_DSHL(block, I1, I1, 32);
UML_DOR(block, I0, I0, I1);
generate_load_operand(block, compiler, LOCAL, src_code, uml::I1, uml::I3);
const int no_shift = compiler.next_label();
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
UML_AND(block, I1, I1, 0x1f);
UML_JMPc(block, uml::COND_Z, no_shift);
UML_SUB(block, I3, 64 - C_SHIFT + 1, I1);
UML_DROLAND(block, I3, I0, I3, C_MASK);
UML_OR(block, I2, I2, I3);
UML_LABEL(block, no_shift);
UML_DSAR(block, I0, I0, I1);
generate_update_nz_d(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
UML_DSHR(block, I1, I0, 32);
UML_STORE(block, (void *)m_core->local_regs, I4, I1, SIZE_DWORD, SCALE_x4);
UML_STORE(block, (void *)m_core->local_regs, I5, I0, SIZE_DWORD, SCALE_x4);
}
void hyperstone_device::generate_sar(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, src_code, uml::I1, uml::I1);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I0, uml::I3);
const int no_shift = compiler.next_label();
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
UML_AND(block, I1, I1, 0x1f);
UML_JMPc(block, uml::COND_Z, no_shift);
UML_SUB(block, I4, 32 - C_SHIFT + 1, I1);
UML_ROLAND(block, I4, I0, I4, C_MASK);
UML_OR(block, I2, I2, I4);
UML_LABEL(block, no_shift);
UML_SAR(block, I0, I0, I1);
generate_update_nz(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
UML_STORE(block, (void *)m_core->local_regs, I3, I0, SIZE_DWORD, SCALE_x4);
}
template <hyperstone_device::shift_type HiN, hyperstone_device::reg_bank DstGlobal>
void hyperstone_device::generate_sari(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t n = HiN ? DRC_HI_N_VALUE : DRC_LO_N_VALUE;
UML_MOV(block, I2, DRC_SR);
if (!DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
if (n)
{
UML_ROLAND(block, I4, I0, 32 - C_SHIFT + 1 - n, C_MASK);
UML_OR(block, I2, I2, I4);
}
UML_SAR(block, I0, I0, n);
generate_update_nz(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
template <hyperstone_device::shift_type HiN>
void hyperstone_device::generate_shldi(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t n = HiN ? DRC_HI_N_VALUE : DRC_LO_N_VALUE;
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I1, uml::I4);
generate_load_operand(block, compiler, LOCAL, dst_code + 1, uml::I0, uml::I5);
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
if (n)
UML_SHR(block, I3, I1, 32 - n);
UML_DSHL(block, I1, I1, 32);
UML_DOR(block, I0, I0, I1);
if (n)
{
UML_ROLAND(block, I1, I3, C_SHIFT, C_MASK);
UML_OR(block, I2, I2, I1);
}
UML_DSHL(block, I0, I0, n);
generate_update_nz_d(block, compiler, uml::I2);
if (n)
{
UML_DTEST(block, I0, ~uint64_t(0));
UML_MOV(block, I1, util::make_bitmask<uint32_t>(n));
UML_MOVc(block, uml::COND_NS, I1, 0);
UML_CMP(block, I3, I1);
UML_MOV(block, I1, V_MASK);
UML_MOVc(block, uml::COND_E, I1, 0);
UML_OR(block, I2, I2, I1);
}
UML_MOV(block, DRC_SR, I2);
UML_DSHR(block, I1, I0, 32);
UML_STORE(block, (void *)m_core->local_regs, I4, I1, SIZE_DWORD, SCALE_x4);
UML_STORE(block, (void *)m_core->local_regs, I5, I0, SIZE_DWORD, SCALE_x4);
}
void hyperstone_device::generate_shld(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
if ((src_code == dst_code) || (src_code == (dst_code + 1)))
{
return; // undefined if Ls overlaps Ld or Ldf
}
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I1, uml::I5);
generate_load_operand(block, compiler, LOCAL, dst_code + 1, uml::I0, uml::I6);
UML_DSHL(block, I1, I1, 32);
UML_DOR(block, I0, I0, I1);
generate_load_operand(block, compiler, LOCAL, src_code, uml::I1, uml::I3);
const int no_shift = compiler.next_label();
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
UML_AND(block, I1, I1, 0x1f);
UML_JMPc(block, uml::COND_Z, no_shift);
UML_SUB(block, I3, 64, I1);
UML_DSHR(block, I4, I0, I3);
UML_ROLINS(block, I2, I4, C_SHIFT, C_MASK);
UML_LABEL(block, no_shift);
UML_DSHL(block, I0, I0, I1);
const int no_overflow = compiler.next_label();
UML_TEST(block, I1, ~uint32_t(0));
UML_JMPc(block, uml::COND_Z, no_overflow);
UML_SHR(block, I1, ~uint32_t(0), I3);
UML_DTEST(block, I0, ~uint64_t(0));
UML_MOVc(block, uml::COND_NS, I1, 0);
UML_CMP(block, I4, I1);
UML_JMPc(block, uml::COND_E, no_overflow);
UML_OR(block, I2, I2, V_MASK);
UML_LABEL(block, no_overflow);
UML_DTEST(block, I0, I0);
generate_update_nz_d(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
UML_DSHR(block, I1, I0, 32);
UML_STORE(block, (void *)m_core->local_regs, I5, I1, SIZE_DWORD, SCALE_x4);
UML_STORE(block, (void *)m_core->local_regs, I6, I0, SIZE_DWORD, SCALE_x4);
}
void hyperstone_device::generate_shl(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
UML_MOV(block, I2, DRC_SR);
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, src_code, uml::I1, uml::I1);
generate_load_operand(block, compiler, LOCAL, dst_code, uml::I0, uml::I3);
const int no_shift = compiler.next_label();
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
UML_AND(block, I1, I1, 0x1f);
UML_JMPc(block, uml::COND_Z, no_shift);
UML_SUB(block, I5, 32, I1);
UML_SHR(block, I4, I0, I5);
UML_ROLINS(block, I2, I4, C_SHIFT, C_MASK);
UML_LABEL(block, no_shift);
UML_SHL(block, I0, I0, I1);
const int no_overflow = compiler.next_label();
UML_TEST(block, I1, ~uint32_t(0));
UML_JMPc(block, uml::COND_Z, no_overflow);
UML_SHR(block, I1, ~uint32_t(0), I5);
UML_TEST(block, I0, ~uint32_t(0));
UML_MOVc(block, uml::COND_NS, I1, 0);
UML_CMP(block, I4, I1);
UML_JMPc(block, uml::COND_E, no_overflow);
UML_OR(block, I2, I2, V_MASK);
UML_LABEL(block, no_overflow);
UML_TEST(block, I0, ~uint32_t(0));
generate_update_nz(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
UML_STORE(block, (void *)m_core->local_regs, I3, I0, SIZE_DWORD, SCALE_x4);
}
template <hyperstone_device::shift_type HiN, hyperstone_device::reg_bank DstGlobal>
void hyperstone_device::generate_shli(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t n = HiN ? DRC_HI_N_VALUE : DRC_LO_N_VALUE;
UML_MOV(block, I2, DRC_SR);
if (!DstGlobal)
UML_ROLAND(block, I3, I2, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I0, uml::I3);
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
if (n)
{
UML_SHR(block, I4, I0, 32 - n);
UML_ROLAND(block, I1, I4, C_SHIFT, C_MASK);
UML_OR(block, I2, I2, I1);
}
UML_SHL(block, I0, I0, n);
generate_update_nz(block, compiler, uml::I2);
if (n)
{
UML_TEST(block, I0, ~uint32_t(0));
UML_MOV(block, I1, util::make_bitmask<uint32_t>(n));
UML_MOVc(block, uml::COND_NS, I1, 0);
UML_CMP(block, I4, I1);
UML_MOV(block, I1, V_MASK);
UML_MOVc(block, uml::COND_E, I1, 0);
UML_OR(block, I2, I2, I1);
}
UML_MOV(block, DRC_SR, I2);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I3, false);
}
void hyperstone_device::generate_testlz(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, LOCAL, src_code, uml::I0, uml::I0);
UML_LZCNT(block, I0, I0);
generate_set_dst(block, compiler, desc, LOCAL, dst_code, uml::I0, uml::I3, true);
}
void hyperstone_device::generate_rol(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t src_code = op & 0xf;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
UML_ADD(block, I2, I3, dst_code);
UML_AND(block, I4, I2, 0x3f);
UML_LOAD(block, I0, (void *)m_core->local_regs, I4, SIZE_DWORD, SCALE_x4); // I0 = dreg
UML_ADD(block, I2, I3, src_code);
UML_AND(block, I1, I2, 0x3f);
UML_LOAD(block, I5, (void *)m_core->local_regs, I1, SIZE_DWORD, SCALE_x4);
UML_AND(block, I1, I5, 0x1f); // I1 = sreg & 0x1f
int no_shift = compiler.next_label();
UML_CMP(block, I1, 0);
UML_JMPc(block, uml::COND_E, no_shift);
UML_ROL(block, I2, I0, I1);
UML_LABEL(block, no_shift);
UML_DSHR(block, I5, 0xffffffff00000000ULL, I1);
UML_AND(block, I3, I0, I5);
UML_MOV(block, I6, 0);
int no_hi_bit = compiler.next_label();
UML_TEST(block, I0, 0x80000000);
UML_JMPc(block, uml::COND_Z, no_hi_bit);
UML_XOR(block, I3, I3, I5);
int done_shift = compiler.next_label();
UML_LABEL(block, no_hi_bit);
UML_TEST(block, I3, ~0);
UML_JMPc(block, uml::COND_Z, done_shift);
UML_OR(block, I6, I6, V_MASK);
UML_LABEL(block, done_shift);
UML_TEST(block, I2, ~uint32_t(0));
UML_SETc(block, uml::COND_Z, I5);
UML_SHL(block, I5, I5, Z_SHIFT);
UML_ROLINS(block, I5, I2, N_SHIFT + 1, N_MASK);
UML_OR(block, I5, I5, I6);
UML_ROLINS(block, DRC_SR, I5, 0, (V_MASK | N_MASK | Z_MASK | C_MASK));
UML_STORE(block, (void *)m_core->local_regs, I4, I2, SIZE_DWORD, SCALE_x4);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_ldxx1(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t srcf_code = src_code + 1;
const uint32_t dst_code = (op & 0xf0) >> 4;
const auto [sub_type, extra_s] = generate_get_d_code_dis(desc);
if (!DstGlobal || !SrcGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
const uml::parameter dstp = generate_load_address_ad(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I0);
switch (sub_type)
{
case 0: // LDBS.D/A
case 1: // LDBU.D/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
generate_add_dis(block, compiler, uml::I0, dstp, extra_s, 1);
UML_CALLH(block, *m_mem_read8);
if (sub_type == 0) // LDBS.D/A
UML_SEXT(block, I1, I1, SIZE_BYTE);
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I1, desc);
}
}
else
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
break;
case 2:
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
generate_add_dis(block, compiler, uml::I0, dstp, extra_s, 2);
UML_CALLH(block, *m_mem_read16);
if (extra_s & 1) // LDHS.A/D
UML_SEXT(block, I1, I1, SIZE_WORD);
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I1, desc);
}
}
else
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
break;
case 3:
generate_add_dis(block, compiler, uml::I0, dstp, extra_s, 4);
switch (extra_s & 3)
{
case 0: // LDW.D/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_CALLH(block, *m_mem_read32);
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I1, desc);
}
}
else
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
break;
case 1: // LDD.D/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
UML_CALLH(block, *m_mem_read32);
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I1, desc);
}
}
else
{
UML_ADD(block, I2, I3, src_code);
UML_AND(block, I2, I2, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I1, SIZE_DWORD, SCALE_x4);
}
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_read32);
if (SrcGlobal)
{
UML_MOV(block, I5, I1);
generate_set_global_register(block, compiler, desc, srcf_code);
}
else
{
UML_ADD(block, I3, I3, srcf_code);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
break;
case 2: // LDW.IOD/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_ROLAND(block, I0, I0, 21, 0x7ffc);
UML_CALLH(block, *m_io_read32);
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == 0)
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I1, desc);
}
}
else
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
break;
case 3: // LDD.IOD/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
UML_ROLAND(block, I0, I0, 21, 0x7ffc);
UML_CALLH(block, *m_io_read32);
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I1, desc);
}
}
else
{
UML_ADD(block, I2, I3, src_code);
UML_AND(block, I2, I2, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I1, SIZE_DWORD, SCALE_x4);
}
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_io_read32);
if (SrcGlobal)
{
UML_MOV(block, I5, I1);
generate_set_global_register(block, compiler, desc, srcf_code);
}
else
{
UML_ADD(block, I3, I3, srcf_code);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
break;
}
break;
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_ldxx2(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t srcf_code = src_code + 1;
const uint32_t dst_code = (op & 0xf0) >> 4;
const auto [sub_type, extra_s] = generate_get_d_code_dis(desc);
if (DstGlobal && (dst_code <= SR_REGISTER))
{
osd_printf_error("Denoted PC or SR in hyperstone_ldxx2. PC = %08X\n", desc->pc);
return;
}
if (!DstGlobal || !SrcGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
generate_load_address_ns(block, compiler, desc, DstGlobal, dst_code, uml::I6, uml::I2, sub_type, extra_s);
switch (sub_type)
{
case 0: // LDBS.N
case 1: // LDBU.N
case 2: // LDHS.N, LDHU.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
if (sub_type == 2)
{
UML_AND(block, I0, I6, ~1);
UML_CALLH(block, *m_mem_read16);
if (extra_s & 1)
UML_SEXT(block, I1, I1, SIZE_WORD);
}
else
{
UML_MOV(block, I0, I6);
UML_CALLH(block, *m_mem_read8);
if (sub_type == 0)
UML_SEXT(block, I1, I1, SIZE_BYTE);
}
generate_set_dst(block, compiler, desc, SrcGlobal, src_code, uml::I1, uml::I3, true);
if ((DstGlobal != SrcGlobal) || (src_code != dst_code))
{
if (sub_type == 2)
UML_ADD(block, I4, I6, extra_s & ~1);
else
UML_ADD(block, I4, I6, extra_s);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I4, uml::I2, false);
}
break;
case 3:
switch (extra_s & 3)
{
case 0: // LDW.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_AND(block, I0, I6, ~3);
UML_CALLH(block, *m_mem_read32);
generate_set_dst(block, compiler, desc, SrcGlobal, src_code, uml::I1, uml::I3, true);
if ((DstGlobal != SrcGlobal) || (src_code != dst_code))
{
UML_ADD(block, I4, I6, extra_s & ~3);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I4, uml::I2, false);
}
break;
case 1: // LDD.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
UML_AND(block, I0, I6, ~3);
UML_CALLH(block, *m_mem_read32);
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_read32);
UML_MOV(block, I5, I1);
generate_set_global_register(block, compiler, desc, srcf_code);
}
else
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_read32);
UML_ADD(block, I3, I3, 1);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
if ((DstGlobal != SrcGlobal) || (src_code != dst_code))
{
UML_ADD(block, I4, I6, extra_s & ~3);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I4, uml::I2, false);
}
break;
case 2: // Reserved
osd_printf_error("Reserved instruction in generate_ldxx2. PC = %08X\n", desc->pc);
break;
case 3: // LDW.S
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_3));
const int below_sp = compiler.next_label();
const int done = compiler.next_label();
UML_CMP(block, I6, mem(&m_core->global_regs[SP_REGISTER]));
UML_JMPc(block, uml::COND_B, below_sp);
UML_ROLAND(block, I0, I6, 32 - 2, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I0, SIZE_DWORD, SCALE_x4);
UML_JMP(block, done);
UML_LABEL(block, below_sp);
UML_AND(block, I0, I6, ~3);
UML_CALLH(block, *m_mem_read32);
UML_LABEL(block, done);
generate_set_dst(block, compiler, desc, SrcGlobal, src_code, uml::I1, uml::I3, true);
if ((DstGlobal != SrcGlobal) || (src_code != dst_code))
{
UML_ADD(block, I4, I6, extra_s & ~3);
generate_set_dst(block, compiler, desc, DstGlobal, dst_code, uml::I4, uml::I2, false);
}
break;
}
}
break;
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_stxx1(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
const auto [sub_type, extra_s] = generate_get_d_code_dis(desc);
if (!DstGlobal || !SrcGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
const uml::parameter dstp = generate_load_address_ad(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I0);
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
UML_MOV(block, I1, 0);
else
UML_MOV(block, I1, mem(&m_core->global_regs[src_code]));
}
else
{
UML_ADD(block, I1, I3, src_code);
UML_AND(block, I1, I1, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I1, SIZE_DWORD, SCALE_x4);
}
switch (sub_type)
{
case 0: // STBS.D/A
case 1: // STBU.D/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
generate_add_dis(block, compiler, uml::I0, dstp, extra_s, 1);
UML_CALLH(block, *m_mem_write8);
if (sub_type == 0)
{
UML_SEXT(block, I0, I1, SIZE_BYTE);
UML_CMP(block, I0, I1);
UML_EXHc(block, uml::COND_NZ, *m_exception, TRAPNO_RANGE_ERROR);
}
break;
case 2: // STHS.D/A, STHU.D/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
generate_add_dis(block, compiler, uml::I0, dstp, extra_s, 2);
UML_CALLH(block, *m_mem_write16);
if (extra_s & 1)
{
UML_SEXT(block, I0, I1, SIZE_WORD);
UML_CMP(block, I0, I1);
UML_EXHc(block, uml::COND_NZ, *m_exception, TRAPNO_RANGE_ERROR);
}
break;
case 3:
generate_add_dis(block, compiler, uml::I0, dstp, extra_s, 4);
switch (extra_s & 3)
{
case 0: // STW.D/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_CALLH(block, *m_mem_write32);
break;
case 1: // STD.D/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
UML_CALLH(block, *m_mem_write32);
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
UML_MOV(block, I1, 0);
else
UML_MOV(block, I1, mem(&m_core->global_regs[src_code + 1]));
}
else
{
UML_ADD(block, I3, I3, src_code + 1);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_write32);
break;
case 2: // STW.IOD/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_ROLAND(block, I0, I0, 21, 0x7ffc);
UML_CALLH(block, *m_io_write32);
break;
case 3: // STD.IOD/A
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
UML_ROLAND(block, I0, I0, 21, 0x7ffc);
UML_CALLH(block, *m_io_write32);
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
UML_MOV(block, I1, 0);
else
UML_MOV(block, I1, mem(&m_core->global_regs[src_code + 1]));
}
else
{
UML_ADD(block, I3, I3, src_code + 1);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_io_write32);
break;
}
break;
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_stxx2(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
const auto [sub_type, extra_s] = generate_get_d_code_dis(desc);
if (DstGlobal && (dst_code <= SR_REGISTER))
{
osd_printf_error("Denoted PC or SR in hyperstone_stxx2. PC = %08X\n", desc->pc);
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
return;
}
if (!DstGlobal || !SrcGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
generate_load_address_ns(block, compiler, desc, DstGlobal, dst_code, uml::I0, uml::I6, sub_type, extra_s);
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
UML_MOV(block, I1, 0);
else
UML_MOV(block, I1, mem(&m_core->global_regs[src_code]));
}
else
{
UML_ADD(block, I1, I3, src_code);
UML_AND(block, I1, I1, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I1, SIZE_DWORD, SCALE_x4);
}
switch (sub_type)
{
case 0: // STBS.N
case 1: // STBU.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_CALLH(block, *m_mem_write8);
UML_ADD(block, I0, I0, extra_s);
if (DstGlobal)
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I0);
else
UML_STORE(block, (void *)m_core->local_regs, I6, I0, SIZE_DWORD, SCALE_x4);
if (sub_type == 0)
{
UML_SEXT(block, I0, I1, SIZE_BYTE);
UML_CMP(block, I0, I1);
UML_EXHc(block, uml::COND_NZ, *m_exception, TRAPNO_RANGE_ERROR);
}
break;
case 2: // STHS.N, STHU.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_MOV(block, I4, I0);
UML_AND(block, I0, I0, ~1);
UML_CALLH(block, *m_mem_write16);
UML_ADD(block, I4, I4, extra_s & ~1);
if (DstGlobal)
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I4);
else
UML_STORE(block, (void *)m_core->local_regs, I6, I4, SIZE_DWORD, SCALE_x4);
if (extra_s & 1)
{
UML_SEXT(block, I0, I1, SIZE_WORD);
UML_CMP(block, I0, I1);
UML_EXHc(block, uml::COND_NZ, *m_exception, TRAPNO_RANGE_ERROR);
}
break;
case 3:
switch (extra_s & 3)
{
case 0: // STW.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_MOV(block, I5, I0);
UML_AND(block, I0, I0, ~3);
UML_CALLH(block, *m_mem_write32);
UML_ADD(block, I5, I5, extra_s);
if (DstGlobal)
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
else
UML_STORE(block, (void *)m_core->local_regs, I6, I5, SIZE_DWORD, SCALE_x4);
break;
case 1: // STD.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
UML_MOV(block, I5, I0);
UML_AND(block, I0, I0, ~3);
UML_CALLH(block, *m_mem_write32);
UML_ADD(block, I5, I5, extra_s & ~1);
if (DstGlobal)
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
else
UML_STORE(block, (void *)m_core->local_regs, I6, I5, SIZE_DWORD, SCALE_x4);
generate_load_operand(block, compiler, SrcGlobal, src_code + 1, uml::I1, uml::I4);
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_write32);
break;
case 2: // Reserved
osd_printf_error("Executed Reserved instruction in hyperstone_stxx2. PC = %08X\n", desc->pc);
break;
case 3: // STW.S
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_3));
int less_than_sp = compiler.next_label();
int store_done = compiler.next_label();
UML_MOV(block, I5, I0);
UML_CMP(block, I5, mem(&SP));
UML_JMPc(block, uml::COND_B, less_than_sp);
UML_ROLAND(block, I4, I0, 30, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I4, I1, SIZE_DWORD, SCALE_x4);
UML_JMP(block, store_done);
UML_LABEL(block, less_than_sp);
UML_AND(block, I0, I0, ~3);
UML_CALLH(block, *m_mem_write32);
UML_LABEL(block, store_done);
UML_ADD(block, I5, I5, extra_s & ~3);
if (DstGlobal)
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
else
UML_STORE(block, (void *)m_core->local_regs, I6, I5, SIZE_DWORD, SCALE_x4);
break;
}
}
break;
}
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal, hyperstone_device::sign_mode SIGNED>
void hyperstone_device::generate_mulsu(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_36));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t dstf_code = dst_code + 1;
const uint32_t src_code = op & 0xf;
if ((SrcGlobal && src_code < 2) || (DstGlobal && dst_code < 2))
{
osd_printf_error("Denoted PC or SR in hyperstone_muls/u instruction. PC = %08X\n", desc->pc);
return;
}
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I0, uml::I4);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I1, uml::I6);
if (SIGNED == IS_SIGNED)
UML_MULS(block, I4, I5, I0, I1);
else
UML_MULU(block, I4, I5, I0, I1);
UML_OR(block, I2, I4, I5);
UML_TEST(block, I2, ~uint32_t(0));
UML_SETc(block, uml::COND_Z, I2);
UML_SHL(block, I2, I2, Z_SHIFT);
UML_ROLINS(block, I2, I5, N_SHIFT + 1, N_MASK);
UML_ROLINS(block, DRC_SR, I2, 0, (N_MASK | Z_MASK));
if (DstGlobal)
{
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
UML_MOV(block, mem(&m_core->global_regs[dstf_code]), I4);
}
else
{
UML_STORE(block, (void *)m_core->local_regs, I6, I5, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I2, I3, dstf_code);
UML_AND(block, I5, I2, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I5, I4, SIZE_DWORD, SCALE_x4);
}
int done = compiler.next_label();
UML_MOV(block, I7, mem(&m_core->clock_cycles_6));
if (SIGNED == IS_SIGNED)
{
UML_CMP(block, I0, 0xffff8000);
UML_JMPc(block, uml::COND_B, done);
UML_CMP(block, I0, 0x00008000);
UML_JMPc(block, uml::COND_AE, done);
UML_CMP(block, I1, 0xffff8000);
UML_JMPc(block, uml::COND_B, done);
UML_CMP(block, I1, 0x00008000);
UML_JMPc(block, uml::COND_AE, done);
}
else
{
UML_CMP(block, I0, 0x0000ffff);
UML_JMPc(block, uml::COND_A, done);
UML_CMP(block, I1, 0x0000ffff);
UML_JMPc(block, uml::COND_A, done);
}
UML_SUB(block, I7, I7, mem(&m_core->clock_cycles_2));
UML_LABEL(block, done);
}
template <hyperstone_device::reg_bank DstGlobal, hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_mul(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
if ((SrcGlobal && src_code < 2) || (DstGlobal && dst_code < 2))
{
osd_printf_error("Denoted PC or SR in hyperstone_mul instruction. PC = %08X\n", desc->pc);
return;
}
if (!SrcGlobal || !DstGlobal)
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
generate_load_operand(block, compiler, SrcGlobal, src_code, uml::I0, uml::I1);
generate_load_operand(block, compiler, DstGlobal, dst_code, uml::I1, uml::I6);
UML_MOV(block, I7, mem(&m_core->clock_cycles_3));
const int add_cycles = compiler.next_label();
const int set_cycles = compiler.next_label();
UML_CMP(block, I0, 0xffff8000);
UML_JMPc(block, uml::COND_L, add_cycles);
UML_CMP(block, I0, 0x00008000);
UML_JMPc(block, uml::COND_GE, add_cycles);
UML_CMP(block, I1, 0xffff8000);
UML_JMPc(block, uml::COND_L, add_cycles);
UML_CMP(block, I1, 0x00008000);
UML_JMPc(block, uml::COND_L, set_cycles);
UML_LABEL(block, add_cycles);
UML_ADD(block, I7, I7, mem(&m_core->clock_cycles_2));
UML_LABEL(block, set_cycles);
UML_MULU(block, I2, I3, I0, I1);
UML_AND(block, I4, DRC_SR, ~(Z_MASK | N_MASK));
UML_TEST(block, I2, ~uint32_t(0));
UML_SETc(block, uml::COND_Z, I5);
UML_SHL(block, I5, I5, Z_SHIFT);
UML_ROLINS(block, I5, I2, N_SHIFT + 1, N_MASK);
UML_ROLINS(block, DRC_SR, I5, 0, (Z_MASK | N_MASK));
if (DstGlobal)
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I2);
else
UML_STORE(block, (void *)m_core->local_regs, I6, I2, SIZE_DWORD, SCALE_x4);
}
template <hyperstone_device::shift_type HiN, hyperstone_device::reg_bank DstGlobal>
void hyperstone_device::generate_set(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint32_t n = op & 0xf;
if (DstGlobal && dst_code < 2)
{
return;
}
if (HiN)
{
if (n >= 4 || n == 2)
{
static const uint32_t set_result[16] = { 0, 0, 0, 0, 0xffffffff, 0, 0xffffffff, 0, 0xffffffff, 0, 0xffffffff, 0, 0xffffffff, 0, 0xffffffff, 0 };
static const uint32_t unset_result[16] = { 0, 0, 0xffffffff, 0, 0, 0xffffffff, 0, 0xffffffff, 0, 0xffffffff, 0, 0xffffffff, 0, 0xffffffff, 0, 0xffffffff };
static const uint32_t mask[16] = { 0, 0, 0, 0, (N_MASK | Z_MASK), (N_MASK | Z_MASK), N_MASK, N_MASK,
(C_MASK | Z_MASK), (C_MASK | Z_MASK), C_MASK, C_MASK, Z_MASK, Z_MASK, V_MASK, V_MASK };
UML_TEST(block, DRC_SR, mask[n]);
UML_MOVc(block, uml::COND_NZ, I0, set_result[n]);
UML_MOVc(block, uml::COND_Z, I0, unset_result[n]);
}
else
{
osd_printf_error("Used reserved N value (%d) in hyperstone_set. PC = %08X\n", n, desc->pc);
return;
}
}
else
{
if (n == 0)
{
int no_low_bit = compiler.next_label();
UML_MOV(block, I1, mem(&m_core->global_regs[SP_REGISTER]));
UML_AND(block, I0, I1, 0xfffffe00);
UML_ROLINS(block, I0, DRC_SR, 32 - FP_SHIFT + 2, 0x000001fc);
UML_TEST(block, I1, 0x100);
UML_JMPc(block, uml::COND_Z, no_low_bit);
UML_TEST(block, DRC_SR, 0x80000000);
UML_JMPc(block, uml::COND_NZ, no_low_bit);
UML_OR(block, I0, I0, 1);
UML_LABEL(block, no_low_bit);
}
else if (n >= 2)
{
static const uint32_t set_result[16] = { 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
static const uint32_t unset_result[16] = { 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 };
static const uint32_t mask[16] = { 0, 0, 0, 0, (N_MASK | Z_MASK), (N_MASK | Z_MASK), N_MASK, N_MASK,
(C_MASK | Z_MASK), (C_MASK | Z_MASK), C_MASK, C_MASK, Z_MASK, Z_MASK, V_MASK, V_MASK };
UML_TEST(block, DRC_SR, mask[n]);
UML_MOVc(block, uml::COND_NZ, I0, set_result[n]);
UML_MOVc(block, uml::COND_Z, I0, unset_result[n]);
}
else
{
osd_printf_error("Used reserved N value (%d) in hyperstone_set. PC = %08X\n", n, desc->pc);
return;
}
}
if (DstGlobal)
{
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I0);
}
else
{
UML_ROLAND(block, I1, DRC_SR, 32 - FP_SHIFT, 0x7f);
UML_ADD(block, I2, I1, dst_code);
UML_AND(block, I3, I2, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I0, SIZE_DWORD, SCALE_x4);
}
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_ldwr(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal || (src_code != dst_code))
generate_load_address_rp(block, compiler, dst_code, uml::I0, uml::I2, 0);
else
generate_load_address_rp(block, compiler, dst_code, uml::I0, uml::I3, 0);
UML_CALLH(block, *m_mem_read32);
if (SrcGlobal || (src_code != dst_code))
generate_set_dst(block, compiler, desc, SrcGlobal, src_code, uml::I1, uml::I3, true);
else
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_lddr(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (!SrcGlobal && (src_code != dst_code))
generate_load_address_rp(block, compiler, dst_code, uml::I0, uml::I2, 0);
else
generate_load_address_rp(block, compiler, dst_code, uml::I0, uml::I3, 0);
UML_CALLH(block, *m_mem_read32);
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_read32);
UML_MOV(block, I5, I1);
generate_set_global_register(block, compiler, desc, src_code + 1);
}
else
{
if (src_code != dst_code)
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
}
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_read32);
UML_ADD(block, I3, I3, 1);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_ldwp(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal || (src_code != dst_code))
generate_load_address_rp(block, compiler, dst_code, uml::I4, uml::I2, 4);
else
generate_load_address_rp(block, compiler, dst_code, uml::I4, uml::I3, 4);
UML_CALLH(block, *m_mem_read32);
if (SrcGlobal || (src_code != dst_code))
{
UML_ADD(block, I4, I4, 4);
UML_STORE(block, (void *)m_core->local_regs, I2, I4, SIZE_DWORD, SCALE_x4);
generate_set_dst(block, compiler, desc, SrcGlobal, src_code, uml::I1, uml::I3, true);
}
else
{
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_lddp(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal || (src_code != dst_code))
generate_load_address_rp(block, compiler, dst_code, uml::I4, uml::I2, 8);
else
generate_load_address_rp(block, compiler, dst_code, uml::I4, uml::I3, 8);
UML_CALLH(block, *m_mem_read32);
if (SrcGlobal || ((src_code != dst_code) && ((src_code + 1) != dst_code)))
{
UML_ADD(block, I4, I4, 8);
UML_STORE(block, (void *)m_core->local_regs, I2, I4, SIZE_DWORD, SCALE_x4);
}
if (SrcGlobal)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_read32);
UML_MOV(block, I5, I1);
generate_set_global_register(block, compiler, desc, src_code + 1);
}
else
{
if (src_code != dst_code)
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
}
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_read32);
UML_ADD(block, I3, I3, 1);
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_stwr(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal || (src_code != dst_code))
generate_load_address_rp(block, compiler, dst_code, uml::I0, uml::I2, 0);
else
generate_load_address_rp(block, compiler, dst_code, uml::I1, uml::I3, 0);
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
UML_MOV(block, I1, 0);
else
UML_MOV(block, I1, mem(&m_core->global_regs[src_code]));
}
else if (src_code != dst_code)
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
UML_CALLH(block, *m_mem_write32);
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_stdr(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal || (src_code != dst_code))
generate_load_address_rp(block, compiler, dst_code, uml::I0, uml::I2, 0);
else
generate_load_address_rp(block, compiler, dst_code, uml::I1, uml::I3, 0);
uml::parameter srcfp = uml::I2;
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
{
UML_MOV(block, I1, 0);
srcfp = uml::I1;
}
else
{
UML_MOV(block, I1, mem(&m_core->global_regs[src_code]));
UML_MOV(block, srcfp, mem(&m_core->global_regs[src_code + 1]));
}
}
else
{
if (src_code != dst_code)
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
UML_ADD(block, I3, I3, 1);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, srcfp, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
UML_CALLH(block, *m_mem_write32);
UML_ADD(block, I0, I0, 4);
if (srcfp != uml::I1)
UML_MOV(block, I1, srcfp);
UML_CALLH(block, *m_mem_write32);
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_stwp(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal || (src_code != dst_code))
generate_load_address_rp(block, compiler, dst_code, uml::I4, uml::I2, 4);
else
generate_load_address_rp(block, compiler, dst_code, uml::I1, uml::I3, 4);
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
UML_MOV(block, I1, 0);
else
UML_MOV(block, I1, mem(&m_core->global_regs[src_code]));
}
else if (src_code != dst_code)
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
UML_CALLH(block, *m_mem_write32);
if (SrcGlobal || (src_code != dst_code))
{
UML_ADD(block, I4, I4, 4);
UML_STORE(block, (void *)m_core->local_regs, I2, I4, SIZE_DWORD, SCALE_x4);
}
else
{
UML_ADD(block, I1, I1, 4);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_stdp(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal || (src_code != dst_code))
generate_load_address_rp(block, compiler, dst_code, uml::I4, uml::I2, 8);
else
generate_load_address_rp(block, compiler, dst_code, uml::I1, uml::I3, 8);
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
UML_MOV(block, I1, 0);
else
UML_MOV(block, I1, mem(&m_core->global_regs[src_code]));
UML_CALLH(block, *m_mem_write32);
UML_ADD(block, I4, I4, 8);
UML_STORE(block, (void *)m_core->local_regs, I2, I4, SIZE_DWORD, SCALE_x4);
if (src_code != SR_REGISTER)
UML_MOV(block, I1, mem(&m_core->global_regs[src_code + 1]));
}
else
{
if (src_code != dst_code)
{
UML_ADD(block, I3, I3, src_code);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
UML_CALLH(block, *m_mem_write32);
if (src_code == dst_code)
{
UML_ADD(block, I1, I1, 8);
UML_STORE(block, (void *)m_core->local_regs, I3, I1, SIZE_DWORD, SCALE_x4);
}
else
{
UML_ADD(block, I4, I4, 8);
UML_STORE(block, (void *)m_core->local_regs, I2, I4, SIZE_DWORD, SCALE_x4);
}
if ((src_code + 1) == dst_code)
{
UML_MOV(block, I1, I4);
}
else
{
UML_ADD(block, I3, I3, 1);
UML_AND(block, I3, I3, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I3, SIZE_DWORD, SCALE_x4);
}
}
UML_ADD(block, I0, I0, 4);
UML_CALLH(block, *m_mem_write32);
}
template <hyperstone_device::branch_condition Condition, hyperstone_device::condition_set CondSet>
void hyperstone_device::generate_b(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
static const uint32_t condition_masks[6] = { V_MASK, Z_MASK, C_MASK, C_MASK | Z_MASK, N_MASK, N_MASK | Z_MASK };
uml::condition_t condition = CondSet ? uml::COND_Z : uml::COND_NZ;
const int skip = compiler.next_label();
UML_TEST(block, DRC_SR, condition_masks[Condition]);
UML_JMPc(block, condition, skip);
generate_br(block, compiler, desc);
UML_LABEL(block, skip);
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
}
void hyperstone_device::generate_br(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint32_t target = generate_get_pcrel(desc);
UML_ADD(block, DRC_PC, DRC_PC, target);
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
generate_branch(block, compiler, compiler.mode(), desc->targetpc, desc);
// TODO: correct cycle count
}
template <hyperstone_device::branch_condition Condition, hyperstone_device::condition_set CondSet>
void hyperstone_device::generate_db(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
static const uint32_t condition_masks[6] = { V_MASK, Z_MASK, C_MASK, C_MASK | Z_MASK, N_MASK, N_MASK | Z_MASK };
const int skip_jump = compiler.next_label();
const int done = compiler.next_label();
UML_TEST(block, DRC_SR, condition_masks[Condition]);
if (CondSet)
UML_JMPc(block, uml::COND_Z, skip_jump);
else
UML_JMPc(block, uml::COND_NZ, skip_jump);
generate_dbr(block, compiler, desc);
UML_JMP(block, done);
UML_LABEL(block, skip_jump);
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_LABEL(block, done);
}
void hyperstone_device::generate_dbr(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_2));
const uint32_t target = generate_get_pcrel(desc);
UML_ADD(block, I0, DRC_PC, target);
UML_MOV(block, mem(&m_core->delay_slot), 1);
UML_MOV(block, mem(&m_core->delay_pc), I0);
UML_MOV(block, mem(&m_core->intblock), 3);
auto const *delayslot = desc->delay.first();
if (delayslot)
{
assert(desc->targetpc != BRANCH_TARGET_DYNAMIC);
assert(!delayslot->next());
UML_ROLINS(block, DRC_SR, ((desc->length >> 1) << ILC_SHIFT) | P_MASK, 0, ILC_MASK | P_MASK);
generate_update_cycles(block);
UML_MOV(block, mem(&m_core->intblock), 2);
#if E132XS_LOG_DRC_REGS
UML_CALLC(block, &c_funcs::dump_registers, this);
#endif
// if we are debugging, call the debugger
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
{
//save_fast_iregs(block);
UML_DEBUG(block, delayslot->pc);
}
// set the PC map variable
UML_MAPVAR(block, MAPVAR_PC, compiler.set_pc(desc->targetpc));
UML_MOV(block, DRC_PC, I0);
UML_MOV(block, mem(&m_core->delay_slot), 0);
UML_MOV(block, mem(&m_core->delay_slot_taken), 1);
if (generate_opcode(block, compiler, delayslot))
{
UML_MOV(block, mem(&m_core->delay_slot_taken), 0);
generate_update_cycles(block);
if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
UML_JMP(block, desc->targetpc | 0x80000000);
else
UML_HASHJMP(block, compiler.mode(), desc->targetpc, *m_nocode);
}
else
{
UML_MOV(block, mem(&m_core->arg0), delayslot->opptr.w[0]);
UML_CALLC(block, &c_funcs::unimplemented, this);
}
}
compiler.m_check_delay = 2;
}
void hyperstone_device::generate_frame(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t dst_code = (op & 0xf0) >> 4;
UML_MOV(block, I2, DRC_SR); // I2 = SR
UML_ROLAND(block, I1, I2, 32 - FP_SHIFT, 0x7f); // I1 = FP -= Ls
UML_SUB(block, I1, I1, op & 0xf);
UML_ROLAND(block, I0, I1, FP_SHIFT, FP_MASK);
UML_OR(block, I0, I0, dst_code << FL_SHIFT); // FL = Ld
UML_ROLINS(block, I2, I0, 0, FP_MASK | FL_MASK | M_MASK); // clear M as well
UML_MOV(block, DRC_SR, I2); // update SR
const int done = compiler.next_label();
UML_AND(block, I0, mem(&SP), ~uint32_t(3));
UML_ADD(block, I1, I1, dst_code ? dst_code : 16); // difference = ((SP & 0x1fc) >> 2) + (64 - 10) - ((GET_FP - SRC_CODE) + GET_FL)
UML_ROLAND(block, I3, I0, 30, 0x7f);
UML_ADD(block, I3, I3, (64 - 10));
UML_SUB(block, I3, I3, I1);
UML_SHL(block, I3, I3, 32 - 7); // sign-extend 7-bit value
UML_SAR(block, I3, I3, 32 - 7);
UML_JMPc(block, uml::COND_NS, done);
UML_CMP(block, I0, mem(&UB)); // check stack pointer against upper bound
UML_SETc(block, uml::COND_AE, I4);
const int push_next = compiler.next_label();
UML_LABEL(block, push_next);
UML_AND(block, I2, I0, 0x3f << 2);
UML_LOAD(block, I1, (void *)m_core->local_regs, I2, SIZE_DWORD, SCALE_x1);
UML_CALLH(block, *m_mem_write32);
UML_ADD(block, I0, I0, 4);
UML_ADD(block, I3, I3, 1);
UML_JMPc(block, uml::COND_S, push_next);
UML_MOV(block, mem(&SP), I0);
UML_TEST(block, I4, ~uint32_t(0));
UML_JMPc(block, uml::COND_Z, done);
UML_ROLINS(block, DRC_SR, ((desc->length >> 1) << ILC_SHIFT) | P_MASK, 0, ILC_MASK | P_MASK);
UML_EXH(block, *m_exception, TRAPNO_FRAME_ERROR);
UML_LABEL(block, done);
}
template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::generate_call(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_ROLINS(block, DRC_SR, ((desc->length >> 1) << ILC_SHIFT) | P_MASK, 0, ILC_MASK | P_MASK);
const uint16_t op = desc->opptr.w[0];
uint16_t imm_1 = m_pr16(desc->pc + 2);
int32_t extra_s = 0;
if (imm_1 & 0x8000)
{
uint16_t imm_2 = m_pr16(desc->pc + 4);
extra_s = imm_2;
extra_s |= ((imm_1 & 0x3fff) << 16);
if (imm_1 & 0x4000)
extra_s |= 0xc0000000;
}
else
{
extra_s = imm_1 & 0x3fff;
if (imm_1 & 0x4000)
extra_s |= 0xffffc000;
}
UML_MOV(block, I1, extra_s);
const uint32_t src_code = op & 0xf;
uint32_t dst_code = (op & 0xf0) >> 4;
if (!dst_code)
dst_code = 16;
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
if (SrcGlobal)
{
if (src_code == SR_REGISTER)
UML_MOV(block, I2, 0);
else
UML_MOV(block, I2, mem(&m_core->global_regs[src_code]));
}
else
{
UML_ADD(block, I4, I3, src_code);
UML_AND(block, I5, I4, 0x3f);
UML_LOAD(block, I2, (void *)m_core->local_regs, I5, SIZE_DWORD, SCALE_x4);
}
UML_AND(block, I4, DRC_PC, ~1);
UML_ROLINS(block, I4, DRC_SR, 32 - S_SHIFT, 1);
UML_ADD(block, I1, I3, dst_code);
UML_AND(block, I6, I1, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I6, I4, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I4, I6, 1);
UML_AND(block, I5, I4, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I5, DRC_SR, SIZE_DWORD, SCALE_x4);
UML_ROLINS(block, DRC_SR, I1, FP_SHIFT, FP_MASK);
UML_ROLINS(block, DRC_SR, 6, FL_SHIFT, FL_MASK);
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
UML_ADD(block, I2, I2, extra_s & ~uint32_t(1));
UML_MOV(block, DRC_PC, I2);
UML_MOV(block, mem(&m_core->intblock), 2);
generate_branch(block, compiler, compiler.mode(), uml::I2, nullptr);
//TODO: add interrupt locks, errors, ....
}
void hyperstone_device::generate_trap_op(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1)); // TODO: with the latency it can change
static const uint32_t conditions[16] = {
0, 0, 0, 0, N_MASK | Z_MASK, N_MASK | Z_MASK, N_MASK, N_MASK, C_MASK | Z_MASK, C_MASK | Z_MASK, C_MASK, C_MASK, Z_MASK, Z_MASK, V_MASK, 0
};
static const bool trap_if_set[16] = {
false, false, false, false, true, false, true, false, true, false, true, false, true, false, true, false
};
const uint16_t op = desc->opptr.w[0];
const uint8_t trapno = (op & 0xfc) >> 2;
const uint8_t code = ((op & 0x300) >> 6) | (op & 0x03);
UML_TEST(block, DRC_SR, conditions[code]);
const int skip_trap = compiler.next_label();
if (trap_if_set[code])
UML_JMPc(block, uml::COND_Z, skip_trap);
else
UML_JMPc(block, uml::COND_NZ, skip_trap);
UML_ROLINS(block, DRC_SR, ((desc->length >> 1) << ILC_SHIFT) | P_MASK, 0, ILC_MASK | P_MASK);
generate_trap_exception_or_int<IS_TRAP>(block, compiler.m_labelnum, trapno);
UML_LABEL(block, skip_trap);
}
void hyperstone_device::generate_extend(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
const uint16_t op = desc->opptr.w[0];
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
const uint16_t func = m_pr16(desc->pc + 2);
UML_ROLAND(block, I3, DRC_SR, 32 - FP_SHIFT, 0x7f);
UML_ADD(block, I2, I3, src_code);
UML_AND(block, I2, I2, 0x3f);
UML_LOAD(block, I0, (void *)m_core->local_regs, I2, SIZE_DWORD, SCALE_x4); // I0: vals
UML_ADD(block, I2, I3, dst_code);
UML_AND(block, I2, I2, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I2, SIZE_DWORD, SCALE_x4); // I1: vald
switch (func)
{
// signed or unsigned multiplication, single word product
case EMUL:
case EMUL_N: // used in "N" type cpu
UML_MULU(block, I2, I3, I0, I1);
UML_MOV(block, mem(&m_core->global_regs[15]), I2);
break;
case EMULU: // unsigned multiplication, double word product
case EMULS: // signed multiplication, double word product
if (func == EMULU)
UML_MULU(block, I2, I3, I0, I1);
else
UML_MULS(block, I2, I3, I0, I1);
UML_MOV(block, mem(&m_core->global_regs[14]), I3);
UML_MOV(block, mem(&m_core->global_regs[15]), I2);
break;
case EMAC: // signed multiply/add, single word product sum
case EMSUB: // signed multiply/substract, single word product difference
UML_MULS(block, I2, I3, I0, I1);
UML_MOV(block, I3, mem(&m_core->global_regs[15]));
if (func == EMAC)
UML_ADD(block, I3, I3, I2);
else
UML_SUB(block, I3, I3, I2);
UML_MOV(block, mem(&m_core->global_regs[15]), I3);
break;
case EMACD: // signed multiply/add, double word product sum
case EMSUBD: // signed multiply/substract, double word product difference
UML_DSEXT(block, I0, I0, SIZE_DWORD);
UML_DSEXT(block, I1, I1, SIZE_DWORD);
UML_DMULS(block, I2, I3, I0, I1);
UML_MOV(block, I3, mem(&m_core->global_regs[14]));
UML_MOV(block, I4, mem(&m_core->global_regs[15]));
UML_DSHL(block, I3, I3, 32);
UML_DOR(block, I3, I3, I4);
if (func == EMACD)
UML_DADD(block, I3, I3, I2);
else
UML_DSUB(block, I3, I3, I2);
UML_MOV(block, mem(&m_core->global_regs[15]), I3);
UML_DSHR(block, I3, I3, 32);
UML_MOV(block, mem(&m_core->global_regs[14]), I3);
break;
// signed half-word multiply/add, single word product sum
case EHMAC:
UML_AND(block, I2, I0, 0x0000ffff);
UML_AND(block, I3, I1, 0x0000ffff);
UML_MULS(block, I2, I3, I2, I3);
UML_SHR(block, I0, I0, 16);
UML_SHR(block, I1, I1, 16);
UML_MULS(block, I0, I1, I0, I1);
UML_ADD(block, I0, I0, I2);
UML_MOV(block, I1, mem(&m_core->global_regs[15]));
UML_ADD(block, I0, I0, I1);
UML_MOV(block, mem(&m_core->global_regs[15]), I0);
break;
// signed half-word multiply/add, double word product sum
case EHMACD:
osd_printf_error("Unimplemented extended opcode, EHMACD, PC = %08x\n", desc->pc);
fatalerror(" ");
break;
// half-word complex multiply
case EHCMULD:
osd_printf_error("Unimplemented extended opcode, EHCMULD, PC = %08x\n", desc->pc);
fatalerror(" ");
break;
// half-word complex multiply/add
case EHCMACD:
osd_printf_error("Unimplemented extended opcode, EHCMACD, PC = %08x\n", desc->pc);
fatalerror(" ");
break;
// half-word (complex) add/subtract
// Ls is not used and should denote the same register as Ld
case EHCSUMD:
osd_printf_error("Unimplemented extended opcode, EHCSUMD, PC = %08x\n", desc->pc);
fatalerror(" ");
break;
// half-word (complex) add/subtract with fixed point adjustment
// Ls is not used and should denote the same register as Ld
case EHCFFTD:
osd_printf_error("Unimplemented extended opcode, EHCFFTD, PC = %08x\n", desc->pc);
fatalerror(" ");
break;
// half-word (complex) add/subtract with fixed point adjustment and shift
// Ls is not used and should denote the same register as Ld
case EHCFFTSD:
osd_printf_error("Unimplemented extended opcode, EHCFFTSD, PC = %08x\n", desc->pc);
fatalerror(" ");
break;
default:
osd_printf_error("Unknown extended opcode (%04x), PC = %08x\n", func, desc->pc);
fatalerror(" ");
break;
}
}
void hyperstone_device::generate_reserved(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
osd_printf_error("Unimplemented: generate_reserved (%08x)\n", desc->pc);
fflush(stdout);
fatalerror(" ");
}
void hyperstone_device::generate_do(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
osd_printf_error("Unimplemented: generate_do (%08x)\n", desc->pc);
fflush(stdout);
fatalerror(" ");
}
#endif // MAME_CPU_E132XS_E132XSDRC_OPS_HXX