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.
This commit is contained in:
Vas Crabb 2025-03-31 04:38:51 +11:00
parent 2fb28016e5
commit eed05ed158
9 changed files with 386 additions and 193 deletions

View File

@ -31,8 +31,7 @@
- GMS30C2232
TODO:
- Pointer error exception on zero address register for interpreter
- Range error exception on store signed byte/half-word
- All instructions should clear the H flag (not just MOV/MOVI)
- Fix behaviour of exceptions in delay slots
- Fix behaviour of branches in delay slots
- Many wrong cycle counts

View File

@ -465,7 +465,7 @@ private:
uint32_t generate_get_pcrel(const opcode_desc *desc);
std::pair<uint16_t, uint32_t> generate_get_d_code_dis(const opcode_desc *opcode);
void generate_get_global_register(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
void generate_get_global_register_high(drcuml_block &block, compiler_state &compiler, uint32_t code, uml::parameter dst);
void generate_set_global_register(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint32_t dst_code);
void generate_set_global_register_low(drcuml_block &block, compiler_state &compiler, uint32_t dst_code, uml::parameter src);
void generate_set_global_register_high(drcuml_block &block, compiler_state &compiler, uint32_t dst_code, uml::parameter src);

View File

@ -26,6 +26,9 @@ public:
compiler_state &operator=(compiler_state const &) = delete;
uint8_t mode() const { return m_mode; }
bool user_mode() const { return !BIT(m_mode, 0); }
bool supervisor_mode() const { return BIT(m_mode, 0); }
bool trace_mode() const { return BIT(m_mode, 1); }
auto next_label() { return m_labelnum++; }
@ -828,7 +831,7 @@ void hyperstone_device::generate_sequence_instruction(drcuml_block &block, compi
--compiler.m_check_delay;
}
if (BIT(compiler.mode(), 1) && !desc->delayslots)
if (compiler.trace_mode() && !desc->delayslots)
UML_EXHc(block, uml::COND_Z, *m_exception, TRAPNO_TRACE_EXCEPTION);
}
else

View File

@ -127,6 +127,29 @@ inline void hyperstone_device::generate_add_dis(drcuml_block &block, compiler_st
}
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
@ -231,7 +254,7 @@ void hyperstone_device::generate_set_global_register_low(drcuml_block &block, co
else if (dst_code == SR_REGISTER)
{
UML_MOV(block, I4, DRC_SR);
if (BIT(compiler.mode(), 0) || (src.is_immediate() && !(src.immediate() & L_MASK)))
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
@ -923,7 +946,7 @@ void hyperstone_device::generate_movd(drcuml_block &block, compiler_state &compi
UML_AND(block, I0, I0, ~uint32_t(1));
UML_MOV(block, DRC_PC, I0);
if (!BIT(compiler.mode(), 0))
if (compiler.user_mode())
{
// privilege exception on setting S or L
UML_XOR(block, I3, I3, ~uint32_t(0));
@ -1288,38 +1311,6 @@ void hyperstone_device::generate_cmp(drcuml_block &block, compiler_state &compil
UML_MOV(block, DRC_SR, I2);
}
void hyperstone_device::generate_get_global_register(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;
int regular_load = compiler.next_label();
int done = compiler.next_label();
UML_TEST(block, DRC_SR, H_MASK);
UML_MOVc(block, uml::COND_NZ, I1, 16 + src_code);
UML_MOVc(block, uml::COND_Z, I1, src_code);
UML_CMP(block, I1, TR_REGISTER);
UML_JMPc(block, uml::COND_NE, regular_load);
UML_SHR(block, I2, mem(&m_core->tr_clocks_per_tick), 1);
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I7);
UML_MOV(block, I7, 0);
UML_CMP(block, mem(&m_core->icount), I2);
UML_MOVc(block, uml::COND_BE, I2, 0);
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I2);
UML_CALLC(block, &c_funcs::compute_tr, this);
UML_MOV(block, I5, mem(&m_core->tr_result));
UML_JMP(block, done);
UML_LABEL(block, regular_load);
UML_LOAD(block, I5, (void *)m_core->global_regs, I1, SIZE_DWORD, SCALE_x4);
UML_SHL(block, I2, 1, I1);
UML_TEST(block, I2, WRITE_ONLY_REGMASK);
UML_MOVc(block, uml::COND_NZ, I5, 0);
UML_LABEL(block, done);
}
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)
{
@ -1329,68 +1320,108 @@ void hyperstone_device::generate_mov(drcuml_block &block, compiler_state &compil
const uint32_t src_code = op & 0xf;
const uint32_t dst_code = (op & 0xf0) >> 4;
int done;
if (DstGlobal)
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())
{
done = compiler.next_label();
if (!BIT(compiler.mode(), 0))
{
const int no_exception = compiler.next_label();
UML_TEST(block, DRC_SR, H_MASK);
UML_JMPc(block, uml::COND_Z, no_exception);
UML_EXH(block, *m_exception, TRAPNO_PRIVILEGE_ERROR);
UML_JMP(block, done);
UML_LABEL(block, no_exception);
}
UML_TEST(block, I2, H_MASK);
UML_EXHc(block, uml::COND_NZ, *m_exception, TRAPNO_PRIVILEGE_ERROR);
}
if (SrcGlobal)
{
generate_get_global_register(block, compiler, desc);
if (!DstGlobal)
UML_ROLAND(block, I1, DRC_SR, 32 - FP_SHIFT, 0x7f);
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_ROLAND(block, I1, DRC_SR, 32 - FP_SHIFT, 0x7f);
UML_ADD(block, I2, I1, src_code);
UML_AND(block, I2, I2, 0x3f);
UML_LOAD(block, I5, (void *)m_core->local_regs, I2, SIZE_DWORD, SCALE_x4);
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_AND(block, DRC_SR, DRC_SR, ~(Z_MASK | N_MASK));
UML_TEST(block, I5, ~0);
UML_SETc(block, uml::COND_Z, I2);
UML_ROLINS(block, DRC_SR, I2, Z_SHIFT, Z_MASK);
UML_ROLINS(block, DRC_SR, I5, N_SHIFT + 1, N_MASK);
UML_TEST(block, I0, ~uint32_t(0));
generate_update_nz(block, compiler, uml::I2);
if (DstGlobal)
{
const int highglobal = compiler.next_label();
UML_TEST(block, DRC_SR, H_MASK);
UML_JMPc(block, uml::COND_NZ, highglobal);
generate_set_global_register_low(block, compiler, dst_code, uml::I5);
if (dst_code == PC_REGISTER)
if (compiler.supervisor_mode())
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
UML_AND(block, I5, I5, ~uint32_t(1));
generate_branch(block, compiler, compiler.mode(), uml::I5, desc);
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);
}
}
UML_JMP(block, done);
UML_LABEL(block, highglobal);
UML_AND(block, DRC_SR, DRC_SR, ~H_MASK);
generate_set_global_register_high(block, compiler, dst_code, uml::I5);
UML_LABEL(block, done);
}
else
{
UML_AND(block, DRC_SR, DRC_SR, ~H_MASK);
UML_ADD(block, I2, I1, dst_code);
UML_AND(block, I2, I2, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I2, I5, SIZE_DWORD, SCALE_x4);
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);
}
}
}
@ -1799,6 +1830,13 @@ void hyperstone_device::generate_movi(drcuml_block &block, compiler_state &compi
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)
@ -1807,48 +1845,55 @@ void hyperstone_device::generate_movi(drcuml_block &block, compiler_state &compi
UML_AND(block, I2, I2, ~V_MASK);
#endif
if (DstGlobal && !BIT(compiler.mode(), 0))
{
const int no_exception = compiler.next_label();
UML_TEST(block, I2, H_MASK);
UML_JMPc(block, uml::COND_Z, no_exception);
UML_EXH(block, *m_exception, TRAPNO_PRIVILEGE_ERROR);
UML_LABEL(block, no_exception);
}
UML_MOV(block, DRC_SR, I2);
if (DstGlobal)
{
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);
generate_set_global_register_low(block, compiler, dst_code, src);
if (dst_code == PC_REGISTER)
if (compiler.supervisor_mode())
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
generate_branch(block, compiler, compiler.mode(), src & ~uint32_t(1), desc);
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_JMP(block, done);
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);
}
}
UML_LABEL(block, highglobal);
UML_AND(block, DRC_SR, DRC_SR, ~H_MASK);
generate_set_global_register_high(block, compiler, dst_code, src);
UML_LABEL(block, done);
}
else
{
UML_AND(block, DRC_SR, DRC_SR, ~H_MASK);
UML_ROLAND(block, I2, DRC_SR, 32 - FP_SHIFT, 0x7f);
UML_ADD(block, I0, I2, dst_code);
UML_AND(block, I0, I0, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I0, src, SIZE_DWORD, SCALE_x4);
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);
}
}
@ -2967,17 +3012,29 @@ void hyperstone_device::generate_stxx1(drcuml_block &block, compiler_state &comp
{
case 0: // STBS.D/A
case 1: // STBU.D/A
// TODO: missing trap on range error for STBS.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
// TODO: missing trap on range error with STHS.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:
@ -3072,38 +3129,52 @@ void hyperstone_device::generate_stxx2(drcuml_block &block, compiler_state &comp
}
else
{
UML_ADD(block, I2, I3, src_code);
UML_AND(block, I5, I2, 0x3f);
UML_LOAD(block, I1, (void *)m_core->local_regs, I5, SIZE_DWORD, SCALE_x4);
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
// TODO: missing trap on range error with STBS.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_CALLH(block, *m_mem_write8);
UML_ADD(block, I0, I0, extra_s);
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
// TODO: missing trap on range error with STHS.N
UML_MOV(block, I7, mem(&m_core->clock_cycles_1));
UML_MOV(block, I5, I0);
UML_MOV(block, I4, I0);
UML_AND(block, I0, I0, ~1);
UML_CALLH(block, *m_mem_write16);
UML_ADD(block, I5, I5, extra_s & ~1);
UML_ADD(block, I4, I4, extra_s & ~1);
if (DstGlobal)
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I4);
else
UML_STORE(block, (void *)m_core->local_regs, I6, I5, SIZE_DWORD, SCALE_x4);
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)
{
@ -3119,6 +3190,7 @@ void hyperstone_device::generate_stxx2(drcuml_block &block, compiler_state &comp
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);
@ -3136,9 +3208,11 @@ void hyperstone_device::generate_stxx2(drcuml_block &block, compiler_state &comp
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));

View File

@ -1553,6 +1553,12 @@ void hyperstone_device::hyperstone_ldxx1()
const uint32_t dst_code = DstGlobal ? DST_CODE : ((DST_CODE + fp) & 0x3f);
const uint32_t dreg = ((DstGlobal && dst_code == SR_REGISTER) ? 0 : (DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code]);
if ((!DstGlobal || (dst_code != SR_REGISTER)) && !dreg)
{
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
switch (sub_type)
{
case 0: // LDBS.D
@ -1667,18 +1673,36 @@ void hyperstone_device::hyperstone_ldxx2()
check_delay_PC();
const uint32_t fp = GET_FP;
const uint32_t src_code = SrcGlobal ? SRC_CODE : (SRC_CODE + fp) & 0x3f;
const uint32_t srcf_code = SrcGlobal ? (src_code + 1) : ((src_code + 1) & 0x3f);
const uint32_t dst_code = DstGlobal ? DST_CODE : (DST_CODE + fp) & 0x3f;
const uint32_t dreg = (DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code];
if (DstGlobal && dst_code < 2)
if (DstGlobal && (dst_code <= SR_REGISTER))
{
m_core->icount -= m_core->clock_cycles_1;
LOG("Denoted PC or SR in hyperstone_ldxx2. PC = %08X\n", PC);
return;
}
const uint32_t src_code = SrcGlobal ? SRC_CODE : (SRC_CODE + fp) & 0x3f;
const uint32_t srcf_code = SrcGlobal ? (src_code + 1) : ((src_code + 1) & 0x3f);
const uint32_t dreg = (DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code];
if (!dreg)
{
switch (sub_type)
{
case 0: // LDBS.N
case 1: // LDBU.N
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += extra_s;
break;
case 2: // LDHS.N, LDHU.N
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += extra_s & ~1;
break;
case 3: // LDW.N, LDD.N, LDW.S
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += extra_s & ~3;
break;
}
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
switch (sub_type)
{
@ -1716,7 +1740,7 @@ void hyperstone_device::hyperstone_ldxx2()
m_core->local_regs[src_code] = READ_HW(dreg);
}
if(DstGlobal != SrcGlobal || src_code != dst_code)
if (DstGlobal != SrcGlobal || src_code != dst_code)
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += (extra_s & ~1);
break;
@ -1817,11 +1841,18 @@ void hyperstone_device::hyperstone_stxx1()
const uint32_t dreg = ((DstGlobal && dst_code == SR_REGISTER) ? 0 : (DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code]);
const uint32_t sreg = ((SrcGlobal && src_code == SR_REGISTER) ? 0 : (SrcGlobal ? m_core->global_regs : m_core->local_regs)[src_code]);
if ((!DstGlobal || (dst_code != SR_REGISTER)) && !dreg)
{
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
switch (sub_type)
{
case 0: // STBS.D
// TODO: missing trap on range error
WRITE_B(dreg + extra_s, (uint8_t)sreg);
WRITE_B(dreg + extra_s, uint8_t(sreg));
if (int8_t(uint8_t(sreg)) != int32_t(sreg))
execute_exception(TRAPNO_RANGE_ERROR);
break;
case 1: // STBU.D
@ -1829,8 +1860,9 @@ void hyperstone_device::hyperstone_stxx1()
break;
case 2: // STHS.D, STHU.D
WRITE_HW(dreg + (extra_s & ~1), (uint16_t)sreg);
// TODO: missing trap on range error with STHS.D
WRITE_HW(dreg + (extra_s & ~1), uint16_t(sreg));
if ((extra_s & 1) && (int16_t(uint16_t(sreg)) != int32_t(sreg)))
execute_exception(TRAPNO_RANGE_ERROR);
break;
case 3:
@ -1907,18 +1939,40 @@ void hyperstone_device::hyperstone_stxx2()
const uint32_t dst_code = DstGlobal ? DST_CODE : ((DST_CODE + fp) & 0x3f);
const uint32_t dreg = (DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code];
if (DstGlobal && dst_code < 2)
if (DstGlobal && (dst_code <= SR_REGISTER))
{
m_core->icount -= m_core->clock_cycles_1;
return;
}
if (!dreg)
{
switch (sub_type)
{
case 0: // LDBS.N
case 1: // LDBU.N
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += extra_s;
break;
case 2: // LDHS.N, LDHU.N
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += extra_s & ~1;
break;
case 3: // LDW.N, LDD.N, LDW.S
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += extra_s & ~3;
break;
}
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
bool range_error;
switch (sub_type)
{
case 0: // STBS.N
// TODO: missing trap on range error
WRITE_B(dreg, (uint8_t)sreg);
range_error = int8_t(uint8_t(sreg)) != int32_t(sreg);
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += extra_s;
if (range_error)
execute_exception(TRAPNO_RANGE_ERROR);
break;
case 1: // STBU.N
@ -1928,8 +1982,10 @@ void hyperstone_device::hyperstone_stxx2()
case 2: // STHS.N, STHU.N
WRITE_HW(dreg, (uint16_t)sreg);
range_error = (extra_s & 1) && (int16_t(uint16_t(sreg)) != int32_t(sreg));
(DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code] += extra_s & ~1;
// TODO: missing trap on range error with STHS.N
if (range_error)
execute_exception(TRAPNO_RANGE_ERROR);
break;
case 3:
@ -2316,11 +2372,20 @@ template <hyperstone_device::reg_bank SrcGlobal>
void hyperstone_device::hyperstone_ldwr()
{
check_delay_PC();
const uint32_t fp = GET_FP;
const uint32_t dreg = m_core->local_regs[(DST_CODE + fp) & 0x3f];
if (!dreg)
{
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
if (SrcGlobal)
set_global_register(SRC_CODE, READ_W(m_core->local_regs[(DST_CODE + fp) & 0x3f]));
set_global_register(SRC_CODE, READ_W(dreg));
else
m_core->local_regs[(SRC_CODE + fp) & 0x3f] = READ_W(m_core->local_regs[(DST_CODE + fp) & 0x3f]);
m_core->local_regs[(SRC_CODE + fp) & 0x3f] = READ_W(dreg);
m_core->icount -= m_core->clock_cycles_1;
}
@ -2333,6 +2398,12 @@ void hyperstone_device::hyperstone_lddr()
const uint32_t src_code = SrcGlobal ? SRC_CODE : ((SRC_CODE + fp) & 0x3f);
const uint32_t dreg = m_core->local_regs[(DST_CODE + fp) & 0x3f];
if (!dreg)
{
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
if (SrcGlobal)
{
set_global_register(src_code, READ_W(dreg));
@ -2354,20 +2425,28 @@ void hyperstone_device::hyperstone_ldwp()
const uint32_t fp = GET_FP;
const uint32_t dst_code = (DST_CODE + fp) & 0x3f;
const uint32_t dreg = m_core->local_regs[dst_code];
if (!dreg)
{
m_core->local_regs[dst_code] = dreg + 4;
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
if (SrcGlobal)
{
set_global_register(SRC_CODE, READ_W(m_core->local_regs[dst_code]));
m_core->local_regs[dst_code] += 4;
set_global_register(SRC_CODE, READ_W(dreg));
m_core->local_regs[dst_code] = dreg + 4;
}
else
{
const uint32_t src_code = (SRC_CODE + fp) & 0x3f;
m_core->local_regs[src_code] = READ_W(m_core->local_regs[dst_code]);
m_core->local_regs[src_code] = READ_W(dreg);
// post increment the destination register if it's different from the source one
// (needed by Hidden Catch)
if (src_code != dst_code)
m_core->local_regs[dst_code] += 4;
m_core->local_regs[dst_code] = dreg + 4;
}
m_core->icount -= m_core->clock_cycles_1;
@ -2383,11 +2462,18 @@ void hyperstone_device::hyperstone_lddp()
const uint32_t dst_code = (DST_CODE + fp) & 0x3f;
const uint32_t dreg = m_core->local_regs[dst_code];
if (!dreg)
{
m_core->local_regs[dst_code] = dreg + 8;
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
if (SrcGlobal)
{
set_global_register(src_code, READ_W(dreg));
set_global_register(src_code + 1, READ_W(dreg + 4));
m_core->local_regs[dst_code] += 8;
m_core->local_regs[dst_code] = dreg + 8;
}
else
{
@ -2398,7 +2484,7 @@ void hyperstone_device::hyperstone_lddp()
// post increment the destination register if it's different from the source one
// and from the "next source" one
if (src_code != dst_code && srcf_code != dst_code)
m_core->local_regs[dst_code] += 8;
m_core->local_regs[dst_code] = dreg + 8;
}
m_core->icount -= m_core->clock_cycles_2;
@ -2412,7 +2498,15 @@ void hyperstone_device::hyperstone_stwr()
const uint32_t fp = GET_FP;
const uint32_t src_code = SrcGlobal ? SRC_CODE : ((SRC_CODE + fp) & 0x3f);
const uint32_t sreg = (SrcGlobal && src_code == SR_REGISTER) ? 0 : (SrcGlobal ? m_core->global_regs : m_core->local_regs)[src_code];
WRITE_W(m_core->local_regs[(DST_CODE + fp) & 0x3f], sreg);
const uint32_t dreg = m_core->local_regs[(DST_CODE + fp) & 0x3f];
if (!dreg)
{
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
WRITE_W(dreg, sreg);
m_core->icount -= m_core->clock_cycles_1;
}
@ -2427,9 +2521,14 @@ void hyperstone_device::hyperstone_stdr()
const uint32_t srcf_code = SrcGlobal ? (SRC_CODE + 1) : ((src_code + 1) & 0x3f);
const uint32_t sreg = (SrcGlobal && src_code == SR_REGISTER) ? 0 : (SrcGlobal ? m_core->global_regs : m_core->local_regs)[src_code];
const uint32_t sregf = (SrcGlobal && src_code == SR_REGISTER) ? 0 : (SrcGlobal ? m_core->global_regs : m_core->local_regs)[srcf_code];
const uint32_t dreg = m_core->local_regs[(DST_CODE + GET_FP) & 0x3f];
if (!dreg)
{
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
WRITE_W(dreg, sreg);
WRITE_W(dreg + 4, sregf);
@ -2444,12 +2543,18 @@ void hyperstone_device::hyperstone_stwp()
const uint32_t fp = GET_FP;
const uint32_t src_code = SrcGlobal ? SRC_CODE : ((SRC_CODE + fp) & 0x3f);
const uint32_t sreg = (SrcGlobal && src_code == SR_REGISTER) ? 0 : (SrcGlobal ? m_core->global_regs : m_core->local_regs)[src_code];
const uint32_t dst_code = (DST_CODE + fp) & 0x3f;
const uint32_t dreg = m_core->local_regs[dst_code];
m_core->local_regs[dst_code] = dreg + 4;
if (!dreg)
{
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
WRITE_W(dreg, sreg);
m_core->local_regs[dst_code] += 4;
m_core->icount -= m_core->clock_cycles_1;
}
@ -2463,13 +2568,18 @@ void hyperstone_device::hyperstone_stdp()
const uint32_t src_code = SrcGlobal ? SRC_CODE : ((SRC_CODE + fp) & 0x3f);
const uint32_t srcf_code = SrcGlobal ? (src_code + 1) : ((src_code + 1) & 0x3f);
const uint32_t sreg = (SrcGlobal && src_code == SR_REGISTER) ? 0 : (SrcGlobal ? m_core->global_regs : m_core->local_regs)[src_code];
const uint32_t dst_code = (DST_CODE + fp) & 0x3f;
const uint32_t dreg = m_core->local_regs[dst_code];
WRITE_W(dreg, sreg);
m_core->local_regs[dst_code] = dreg + 8;
m_core->local_regs[dst_code] += 8;
if (!dreg)
{
execute_exception(TRAPNO_POINTER_ERROR);
return;
}
WRITE_W(dreg, sreg);
const uint32_t sregf = (SrcGlobal && src_code == SR_REGISTER) ? 0 : (SrcGlobal ? m_core->global_regs : m_core->local_regs)[srcf_code];

View File

@ -73,10 +73,10 @@ uint32_t v60_device::opCVTSW()
val = u2f(m_op1);
switch (TKCW & 7)
{
case 0: m_modwritevalw = (uint32_t)(int64_t)round(val); break;
case 1: m_modwritevalw = (uint32_t)(int64_t)floor(val); break;
case 2: m_modwritevalw = (uint32_t)(int64_t)ceil(val); break;
default: m_modwritevalw = (uint32_t)(int64_t)trunc(val); break;
case 0: m_modwritevalw = (uint32_t)llroundf(val); break;
case 1: m_modwritevalw = (uint32_t)(int64_t)floorf(val); break;
case 2: m_modwritevalw = (uint32_t)(int64_t)ceilf(val); break;
default: m_modwritevalw = (uint32_t)(int64_t)truncf(val); break;
}
_S = ((m_modwritevalw & 0x80000000) != 0);

View File

@ -48,17 +48,19 @@ Official test program from pages 4 to 8 of the operator's manual:
#include "emu.h"
#include "cpu/i8085/i8085.h"
#include "machine/i8251.h"
#include "machine/clock.h"
#include "machine/timer.h"
#include "bus/heathzenith/intr_cntrl/intr_cntrl.h"
#include "bus/rs232/rs232.h"
#include "cpu/i8085/i8085.h"
#include "imagedev/cassette.h"
#include "machine/clock.h"
#include "machine/i8251.h"
#include "machine/timer.h"
#include "sound/beep.h"
#include "speaker.h"
#include "bus/heathzenith/intr_cntrl/intr_cntrl.h"
#include "formats/h8_cas.h"
#include "h8.lh"
namespace {

View File

@ -25,28 +25,28 @@ tzbx15_device::tzbx15_device(const machine_config &mconfig, device_type type, co
{
}
tzbx15_device::tzbx15_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, u32 clock, u32 clut_size)
tzbx15_device::tzbx15_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 clut_size)
: tzbx15_device(mconfig, type, tag, owner, clock)
{
m_rom_clut_size = clut_size;
}
tzb215_device::tzb215_device(const machine_config& mconfig, const char* tag, device_t* owner, u32 clock, u32 clut_size)
tzb215_device::tzb215_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, u32 clut_size)
: tzbx15_device(mconfig, TZB215_SPRITES, tag, owner, clock, clut_size)
{
}
tzb215_device::tzb215_device(const machine_config& mconfig, const char* tag, device_t* owner, u32 clock)
tzb215_device::tzb215_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: tzbx15_device(mconfig, TZB215_SPRITES, tag, owner, clock, 0)
{
}
tzb315_device::tzb315_device(const machine_config& mconfig, const char* tag, device_t* owner, u32 clock, u32 clut_size)
tzb315_device::tzb315_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, u32 clut_size)
: tzbx15_device(mconfig, TZB315_SPRITES, tag, owner, clock, clut_size)
{
}
tzb315_device::tzb315_device(const machine_config& mconfig, const char* tag, device_t* owner, u32 clock)
tzb315_device::tzb315_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: tzbx15_device(mconfig, TZB315_SPRITES, tag, owner, clock, 0)
{
}
@ -54,14 +54,6 @@ tzb315_device::tzb315_device(const machine_config& mconfig, const char* tag, dev
void tzbx15_device::common_init()
{
m_rom_clut_offset = memregion("sprites_l")->bytes() - m_rom_clut_size;
m_shadow_pen_array = make_unique_clear<uint8_t[]>(m_rom_clut_size * 2);
m_temp_bitmap.allocate(512, 512);
}
static const gfx_layout spritelayout =
{
8,8,
@ -80,7 +72,11 @@ GFXDECODE_END
void tzbx15_device::device_start()
{
common_init();
m_rom_clut_offset = memregion("sprites_l")->bytes() - m_rom_clut_size;
m_shadow_pen_array = make_unique_clear<uint8_t[]>(m_rom_clut_size * 2);
m_temp_bitmap.allocate(512, 512);
decode_gfx(gfxinfo);
gfx(0)->set_colors(m_rom_clut_size / 8);
gfx(1)->set_colors(m_rom_clut_size / 8);
@ -130,7 +126,7 @@ void tzbx15_device::mycopyrozbitmap_core(bitmap_rgb32 &bitmap, const bitmap_rgb3
int x = sx;
uint32_t cx = startx;
uint32_t cy = starty;
uint32_t* dest = &bitmap.pix(sy, sx);
uint32_t *dest = &bitmap.pix(sy, sx);
while (x <= ex)
{
@ -155,9 +151,12 @@ void tzbx15_device::mycopyrozbitmap_core(bitmap_rgb32 &bitmap, const bitmap_rgb3
}
template<class BitmapClass>
void tzbx15_device::roundupt_drawgfxzoomrotate( BitmapClass &dest_bmp, const rectangle &clip,
gfx_element *gfx, uint32_t code,uint32_t color,int flipx,int flipy,uint32_t ssx,uint32_t ssy,
int scalex, int scaley, int rotate, int write_priority_only )
void tzbx15_device::roundupt_drawgfxzoomrotate(
BitmapClass &dest_bmp, const rectangle &clip,
gfx_element *gfx, uint32_t code, uint32_t color,
int flipx, int flipy, uint32_t ssx, uint32_t ssy,
int scalex, int scaley, int rotate,
int write_priority_only)
{
if (!scalex || !scaley) return;
@ -172,7 +171,7 @@ void tzbx15_device::roundupt_drawgfxzoomrotate( BitmapClass &dest_bmp, const rec
rectangle myclip = clip;
myclip &= dest_bmp.cliprect();
if( gfx )
if (gfx)
{
const pen_t *pal = &m_palette_clut->pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors()));
const uint8_t *shadow_pens = m_shadow_pen_array.get() + (gfx->granularity() * (color % gfx->colors()));
@ -417,23 +416,27 @@ void tzbx15_device::draw_sprites_main(BitmapClass &bitmap, const rectangle &clip
src1 += 4;
int h = 0;
while (lines > 0) {
while (lines > 0)
{
int base, x_offs, x_width, x_pos, draw_this_line = 1;
int this_extent = 0;
/* Odd and even lines come from different banks */
if (h & 1) {
if (h & 1)
{
x_width = src1[0] + 1;
x_offs = src1[1] * scale * 8;
base = src1[2] | (src1[3] << 8);
}
else {
else
{
x_width = src2[0] + 1;
x_offs = src2[1] * scale * 8;
base = src2[2] | (src2[3] << 8);
}
if (draw_this_line) {
if (draw_this_line)
{
base *= 2;
if (!rotate)
@ -446,7 +449,8 @@ void tzbx15_device::draw_sprites_main(BitmapClass &bitmap, const rectangle &clip
else
x_pos = x_offs;
for (int w = 0; w < x_width; w++) {
for (int w = 0; w < x_width; w++)
{
if (rotate)
roundupt_drawgfxzoomrotate(
m_temp_bitmap,cliprect,gfx(0 + (base & 1)),

View File

@ -15,8 +15,8 @@ public:
template <typename T> void set_basepalette(T &&tag) { m_palette_base.set_tag(std::forward<T>(tag)); }
template <typename T> void set_spriteram(T &&tag) { m_spriteram.set_tag(std::forward<T>(tag)); }
void draw_sprites(bitmap_rgb32& bitmap, const rectangle& cliprect, int write_priority_only, int rambank);
void draw_sprites(bitmap_ind8& bitmap, const rectangle& cliprect, int write_priority_only, int rambank);
void draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect, int write_priority_only, int rambank);
void draw_sprites(bitmap_ind8 &bitmap, const rectangle &cliprect, int write_priority_only, int rambank);
void update_cluts();
@ -31,8 +31,6 @@ private:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
void common_init() ATTR_COLD;
void mycopyrozbitmap_core(bitmap_ind8 &bitmap, const bitmap_rgb32 &srcbitmap,
int dstx, int dsty, int srcwidth, int srcheight, int incxx, int incxy, int incyx, int incyy,
const rectangle &clip, int transparent_color);
@ -41,9 +39,12 @@ private:
const rectangle &clip, int transparent_color);
template<class BitmapClass> void draw_sprites_main(BitmapClass &bitmap, const rectangle &cliprect, int write_priority_only, int rambank);
template<class BitmapClass> inline void roundupt_drawgfxzoomrotate( BitmapClass &dest_bmp, const rectangle &clip,
gfx_element *gfx, uint32_t code,uint32_t color,int flipx,int flipy,uint32_t ssx,uint32_t ssy,
int scalex, int scaley, int rotate, int write_priority_only );
template<class BitmapClass> void roundupt_drawgfxzoomrotate(
BitmapClass &dest_bmp, const rectangle &clip,
gfx_element *gfx, uint32_t code, uint32_t color,
int flipx, int flipy, uint32_t ssx, uint32_t ssy,
int scalex, int scaley, int rotate,
int write_priority_only);
DECLARE_GFXDECODE_MEMBER(gfxinfo);