summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/sharc/sharcdrc.cpp
diff options
context:
space:
mode:
author Ville Linde <villedevs@gmail.com>2016-06-07 21:01:31 +0300
committer Ville Linde <villedevs@gmail.com>2016-06-07 21:05:44 +0300
commit7fe3b170be49d89f5ecfd1fdfec4504797f2949a (patch)
treeec6e14ce57166a9b487c6dafdad5448ea7fc5c2b /src/devices/cpu/sharc/sharcdrc.cpp
parent33db0678932ffb0640b05c6f5b48268d60d0f87b (diff)
sharcdrc: Model 2 compatibility (nw)
Diffstat (limited to 'src/devices/cpu/sharc/sharcdrc.cpp')
-rw-r--r--src/devices/cpu/sharc/sharcdrc.cpp347
1 files changed, 333 insertions, 14 deletions
diff --git a/src/devices/cpu/sharc/sharcdrc.cpp b/src/devices/cpu/sharc/sharcdrc.cpp
index da300eafced..b7874d87d91 100644
--- a/src/devices/cpu/sharc/sharcdrc.cpp
+++ b/src/devices/cpu/sharc/sharcdrc.cpp
@@ -1366,6 +1366,57 @@ void adsp21062_device::generate_sequence_instruction(drcuml_block *block, compil
UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE
}
+ // handle a special case where call is used as the last operation in a loop
+ if (desc->userflags & OP_USERFLAG_CALL && desc->userflags & (OP_USERFLAG_COND_LOOP | OP_USERFLAG_COUNTER_LOOP))
+ {
+ if (desc->userflags & OP_USERFLAG_COUNTER_LOOP)
+ {
+ code_label end = compiler->labelnum++;
+ UML_LOAD(block, I0, m_core->lastack, LSTKP, SIZE_DWORD, SCALE_x4);
+ UML_CMP(block, I0, desc->pc);
+ UML_JMPc(block, COND_NE, end);
+
+ code_label label_expire = compiler->labelnum++;
+ UML_MOV(block, I1, mem(&m_core->lstkp)); // mov i1,[m_core->lstkp]
+ UML_LOAD(block, I0, m_core->lcstack, I1, SIZE_DWORD, SCALE_x4); // load i0,m_core->lcstack,i1,dword,scale_x4
+ UML_SUB(block, I0, I0, 1); // sub i0,1
+ UML_STORE(block, m_core->lcstack, I1, I0, SIZE_DWORD, SCALE_x4); // store m_core->lcstack,i1,i0,dword,scale_x4
+ UML_SUB(block, CURLCNTR, CURLCNTR, 1); // sub CURLCNTR,1
+ UML_JMPc(block, COND_E, label_expire); // jne label_expire
+
+ UML_MOV(block, mem(&m_core->temp_return), desc->userdata0);
+ UML_JMP(block, end);
+
+ UML_LABEL(block, label_expire); // label_expire:
+ UML_CALLH(block, *m_pop_pc); // callh m_pop_pc
+ UML_CALLH(block, *m_pop_loop); // callh m_pop_loop
+ UML_MOV(block, mem(&m_core->temp_return), desc->pc + 1);
+
+ UML_LABEL(block, end);
+ }
+ if (desc->userflags & OP_USERFLAG_COND_LOOP)
+ {
+ code_label end = compiler->labelnum++;
+ UML_LOAD(block, I0, m_core->lastack, LSTKP, SIZE_DWORD, SCALE_x4);
+ UML_CMP(block, I0, desc->pc);
+ UML_JMPc(block, COND_NE, end);
+
+ code_label label_expire = compiler->labelnum++;
+
+ int condition = (desc->userflags & OP_USERFLAG_COND_FIELD) >> OP_USERFLAG_COND_FIELD_SHIFT;
+ generate_do_condition(block, compiler, desc, condition, label_expire, m_core->astat_delay_copy);
+ UML_MOV(block, mem(&m_core->temp_return), desc->userdata0);
+ UML_JMP(block, end);
+
+ UML_LABEL(block, label_expire);
+ UML_CALLH(block, *m_pop_pc);
+ UML_CALLH(block, *m_pop_loop);
+ UML_MOV(block, mem(&m_core->temp_return), desc->pc + 1);
+
+ UML_LABEL(block, end);
+ }
+ }
+
/* if this is an invalid opcode, generate the exception now */
// if (desc->flags & OPFLAG_INVALID_OPCODE)
// UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000
@@ -1432,7 +1483,7 @@ void adsp21062_device::generate_sequence_instruction(drcuml_block *block, compil
UML_SUB(block, CURLCNTR, CURLCNTR, 1); // sub CURLCNTR,1
UML_JMPc(block, COND_E, label_expire); // jne label_expire
- generate_jump(block, compiler, desc, false, false, false);
+ generate_loop_jump(block, compiler, desc);
UML_LABEL(block, label_expire); // label_expire:
UML_CALLH(block, *m_pop_pc); // callh m_pop_pc
@@ -1452,7 +1503,7 @@ void adsp21062_device::generate_sequence_instruction(drcuml_block *block, compil
int condition = (desc->userflags & OP_USERFLAG_COND_FIELD) >> OP_USERFLAG_COND_FIELD_SHIFT;
generate_do_condition(block, compiler, desc, condition, label_expire, m_core->astat_delay_copy);
- generate_jump(block, compiler, desc, false, false, false);
+ generate_loop_jump(block, compiler, desc);
UML_LABEL(block, label_expire);
UML_CALLH(block, *m_pop_pc);
@@ -1786,10 +1837,18 @@ void adsp21062_device::generate_call(drcuml_block *block, compiler_state *compil
generate_sequence_instruction(block, &compiler_temp, desc->delay.last(), true);
}
- if (delayslot)
- UML_MOV(block, I0, desc->pc + 3);
+ // if this is the last instruction of a loop, we need to use the return PC from the resolved loop
+ if (desc->userflags & OP_USERFLAG_CALL && desc->userflags & (OP_USERFLAG_COND_LOOP | OP_USERFLAG_COUNTER_LOOP))
+ {
+ UML_MOV(block, I0, mem(&m_core->temp_return));
+ }
else
- UML_MOV(block, I0, desc->pc + 1);
+ {
+ if (delayslot)
+ UML_MOV(block, I0, desc->pc + 3);
+ else
+ UML_MOV(block, I0, desc->pc + 1);
+ }
UML_CALLH(block, *m_push_pc);
// update cycles and hash jump
@@ -1878,6 +1937,23 @@ void adsp21062_device::generate_jump(drcuml_block *block, compiler_state *compil
UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
}
+void adsp21062_device::generate_loop_jump(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ // update cycles and hash jump
+ generate_update_cycles(block, compiler, desc->userdata0, TRUE);
+ /*
+ if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
+ UML_JMP(block, desc->targetpc | 0x80000000); // jmp targetpc | 0x80000000
+ else
+ UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp 0,targetpc,nocode
+ */
+ UML_HASHJMP(block, 0, desc->userdata0, *m_nocode);
+
+ /* reset the mapvar to the current cycles and account for skipped slots */
+ compiler->cycles += desc->skipslots;
+ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
+}
+
/*-------------------------------------------------
generate_write_ureg - UREG is read into I0
-------------------------------------------------*/
@@ -2734,8 +2810,51 @@ int adsp21062_device::generate_opcode(drcuml_block *block, compiler_state *compi
compiler->mode1_delay.data = data;
compiler->mode1_delay.mode = MODE1_SET;
break;
- case 0xc: // ASTAT
- return FALSE;
+ case 0xc: // ASTAT
+ // TODO: does this need delay?
+ if (data & ASTAT_FLAGS::AZ)
+ UML_MOV(block, ASTAT_AZ, 1);
+ if (data & ASTAT_FLAGS::AV)
+ UML_MOV(block, ASTAT_AV, 1);
+ if (data & ASTAT_FLAGS::AN)
+ UML_MOV(block, ASTAT_AN, 1);
+ if (data & ASTAT_FLAGS::AC)
+ UML_MOV(block, ASTAT_AC, 1);
+ if (data & ASTAT_FLAGS::AS)
+ UML_MOV(block, ASTAT_AS, 1);
+ if (data & ASTAT_FLAGS::AI)
+ UML_MOV(block, ASTAT_AI, 1);
+ if (data & ASTAT_FLAGS::MN)
+ UML_MOV(block, ASTAT_MN, 1);
+ if (data & ASTAT_FLAGS::MV)
+ UML_MOV(block, ASTAT_MV, 1);
+ if (data & ASTAT_FLAGS::MU)
+ UML_MOV(block, ASTAT_MU, 1);
+ if (data & ASTAT_FLAGS::MI)
+ UML_MOV(block, ASTAT_MI, 1);
+ if (data & ASTAT_FLAGS::AF)
+ UML_MOV(block, ASTAT_AF, 1);
+ if (data & ASTAT_FLAGS::SV)
+ UML_MOV(block, ASTAT_SV, 1);
+ if (data & ASTAT_FLAGS::SZ)
+ UML_MOV(block, ASTAT_SZ, 1);
+ if (data & ASTAT_FLAGS::SS)
+ UML_MOV(block, ASTAT_SS, 1);
+ if (data & ASTAT_FLAGS::BTF)
+ UML_MOV(block, ASTAT_BTF, 1);
+ if (data & ASTAT_FLAGS::FLG0)
+ UML_MOV(block, FLAG0, 1);
+ if (data & ASTAT_FLAGS::FLG1)
+ UML_MOV(block, FLAG1, 1);
+ if (data & ASTAT_FLAGS::FLG2)
+ UML_MOV(block, FLAG2, 1);
+ if (data & ASTAT_FLAGS::FLG3)
+ UML_MOV(block, FLAG3, 1);
+ if (data & 0xff000000)
+ {
+ UML_OR(block, mem(&m_core->astat_drc.cacc), mem(&m_core->astat_drc.cacc), (data >> 24));
+ }
+ break;
case 0xd: // IMASK
UML_OR(block, IMASK, IMASK, data);
break;
@@ -2773,7 +2892,50 @@ int adsp21062_device::generate_opcode(drcuml_block *block, compiler_state *compi
compiler->mode1_delay.mode = MODE1_CLEAR;
break;
case 0xc: // ASTAT
- return FALSE;
+ // TODO: does this need delay?
+ if (data & ASTAT_FLAGS::AZ)
+ UML_MOV(block, ASTAT_AZ, 0);
+ if (data & ASTAT_FLAGS::AV)
+ UML_MOV(block, ASTAT_AV, 0);
+ if (data & ASTAT_FLAGS::AN)
+ UML_MOV(block, ASTAT_AN, 0);
+ if (data & ASTAT_FLAGS::AC)
+ UML_MOV(block, ASTAT_AC, 0);
+ if (data & ASTAT_FLAGS::AS)
+ UML_MOV(block, ASTAT_AS, 0);
+ if (data & ASTAT_FLAGS::AI)
+ UML_MOV(block, ASTAT_AI, 0);
+ if (data & ASTAT_FLAGS::MN)
+ UML_MOV(block, ASTAT_MN, 0);
+ if (data & ASTAT_FLAGS::MV)
+ UML_MOV(block, ASTAT_MV, 0);
+ if (data & ASTAT_FLAGS::MU)
+ UML_MOV(block, ASTAT_MU, 0);
+ if (data & ASTAT_FLAGS::MI)
+ UML_MOV(block, ASTAT_MI, 0);
+ if (data & ASTAT_FLAGS::AF)
+ UML_MOV(block, ASTAT_AF, 0);
+ if (data & ASTAT_FLAGS::SV)
+ UML_MOV(block, ASTAT_SV, 0);
+ if (data & ASTAT_FLAGS::SZ)
+ UML_MOV(block, ASTAT_SZ, 0);
+ if (data & ASTAT_FLAGS::SS)
+ UML_MOV(block, ASTAT_SS, 0);
+ if (data & ASTAT_FLAGS::BTF)
+ UML_MOV(block, ASTAT_BTF, 0);
+ if (data & ASTAT_FLAGS::FLG0)
+ UML_MOV(block, FLAG0, 0);
+ if (data & ASTAT_FLAGS::FLG1)
+ UML_MOV(block, FLAG1, 0);
+ if (data & ASTAT_FLAGS::FLG2)
+ UML_MOV(block, FLAG2, 0);
+ if (data & ASTAT_FLAGS::FLG3)
+ UML_MOV(block, FLAG3, 0);
+ if (data & 0xff000000)
+ {
+ UML_AND(block, mem(&m_core->astat_drc.cacc), mem(&m_core->astat_drc.cacc), ~(data >> 24));
+ }
+ break;
case 0xd: // IMASK
UML_AND(block, IMASK, IMASK, ~data);
break;
@@ -2961,7 +3123,77 @@ int adsp21062_device::generate_opcode(drcuml_block *block, compiler_state *compi
case 1: // compute / dreg <-> DM / dreg <-> PM |001|
{
- return FALSE;
+ int pm_dreg = (opcode >> 23) & 0xf;
+ int pmm = (opcode >> 27) & 0x7;
+ int pmi = (opcode >> 30) & 0x7;
+ int dm_dreg = (opcode >> 33) & 0xf;
+ int dmm = (opcode >> 38) & 0x7;
+ int dmi = (opcode >> 41) & 0x7;
+ int pmd = (opcode >> 37) & 0x1;
+ int dmd = (opcode >> 44) & 0x1;
+ int compute = opcode & 0x7fffff;
+
+ bool temp_pm_dreg = false;
+ if (compute != 0 && pmd && desc->regout[0] & (1 << pm_dreg))
+ {
+ UML_MOV(block, mem(&m_core->dreg_temp), REG(pm_dreg));
+ temp_pm_dreg = true;
+ }
+ bool temp_dm_dreg = false;
+ if (compute != 0 && dmd && desc->regout[0] & (1 << dm_dreg))
+ {
+ UML_MOV(block, mem(&m_core->dreg_temp2), REG(dm_dreg));
+ temp_dm_dreg = true;
+ }
+
+ generate_compute(block, compiler, desc);
+
+ // PM transfer
+ if (pmd)
+ {
+ // dreg -> PM
+ if (temp_pm_dreg)
+ UML_MOV(block, I0, mem(&m_core->dreg_temp));
+ else
+ UML_MOV(block, I0, REG(pm_dreg));
+ UML_MOV(block, I1, PM_I(pmi));
+ UML_CALLH(block, *m_pm_write32);
+ UML_ADD(block, PM_I(pmi), PM_I(pmi), PM_M(pmm));
+ generate_update_circular_buffer(block, compiler, desc, 1, pmi);
+ }
+ else
+ {
+ // PM -> dreg
+ UML_MOV(block, I1, PM_I(pmi));
+ UML_CALLH(block, *m_pm_read32);
+ UML_MOV(block, REG(pm_dreg), I0);
+ UML_ADD(block, PM_I(pmi), PM_I(pmi), PM_M(pmm));
+ generate_update_circular_buffer(block, compiler, desc, 1, pmi);
+ }
+
+ // DM transfer
+ if (dmd)
+ {
+ // dreg -> DM
+ if (temp_dm_dreg)
+ UML_MOV(block, I0, mem(&m_core->dreg_temp2));
+ else
+ UML_MOV(block, I0, REG(dm_dreg));
+ UML_MOV(block, I1, DM_I(dmi));
+ UML_CALLH(block, *m_dm_write32);
+ UML_ADD(block, DM_I(dmi), DM_I(dmi), DM_M(dmm));
+ generate_update_circular_buffer(block, compiler, desc, 0, dmi);
+ }
+ else
+ {
+ // DM -> dreg
+ UML_MOV(block, I1, DM_I(dmi));
+ UML_CALLH(block, *m_dm_read32);
+ UML_MOV(block, REG(dm_dreg), I0);
+ UML_ADD(block, DM_I(dmi), DM_I(dmi), DM_M(dmm));
+ generate_update_circular_buffer(block, compiler, desc, 0, dmi);
+ }
+ return TRUE;
}
case 2: // compute / ureg <-> DM|PM, register modify |010|
@@ -3184,7 +3416,31 @@ int adsp21062_device::generate_opcode(drcuml_block *block, compiler_state *compi
{
if (opcode & U64(0x100000000000)) // immediate data -> DM|PM |100|1|
{
- return FALSE;
+ int i = (opcode >> 41) & 0x7;
+ int m = (opcode >> 38) & 0x7;
+ int g = (opcode >> 37) & 0x1;
+ UINT32 data = (UINT32)opcode;
+
+ if (g)
+ {
+ // PM
+ UML_MOV(block, I0, data);
+ UML_MOV(block, I1, PM_I(i));
+ UML_CALLH(block, *m_pm_write32);
+ UML_ADD(block, PM_I(i), PM_I(i), PM_M(m));
+ }
+ else
+ {
+ // DM
+ UML_MOV(block, I0, data);
+ UML_MOV(block, I1, DM_I(i));
+ UML_CALLH(block, *m_dm_write32);
+ UML_ADD(block, DM_I(i), DM_I(i), DM_M(m));
+ }
+
+ generate_update_circular_buffer(block, compiler, desc, g, i);
+
+ return TRUE;
}
else // immediate shift / dreg <-> DM|PM |100|0|
{
@@ -3865,7 +4121,6 @@ void adsp21062_device::generate_compute(drcuml_block *block, compiler_state *com
case 0x92: // Fn = ABS(Fx - Fy)
case 0x89: // Fn = (Fx + Fy) / 2
case 0xdd: // Rn = TRUNC Fx BY Ry
- case 0xe3: // Fn = CLIP Fx BY Fy
case 0xe0: // Fn = Fx COPYSIGN Fy
case 0x05: // Rn = Rx + Ry + CI
case 0x06: // Rn = Rx - Ry + CI - 1
@@ -3873,7 +4128,6 @@ void adsp21062_device::generate_compute(drcuml_block *block, compiler_state *com
case 0x26: // Rn = Rx + CI - 1
case 0x30: // Rn = ABS Rx
case 0x43: // Rn = NOT Rx
- case 0xb0: // Fn = ABS(Fx)
case 0xa5: // Fn = RND Fx
case 0xad: // Rn = MANT Fx
case 0xcd: // Rn = TRUNC Fx
@@ -4147,6 +4401,19 @@ void adsp21062_device::generate_compute(drcuml_block *block, compiler_state *com
if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO
return;
+ case 0xb0: // Fn = ABS(Fx)
+ UML_FSCOPYI(block, F0, REG(rx));
+ UML_FSABS(block, F0, F0);
+ UML_ICOPYFS(block, REG(rn), F0);
+
+ if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 0); // TODO
+ if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0);
+ if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
+ if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
+ if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); // TODO
+ if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO
+ return;
+
case 0xbd: // Fn = SCALB Fx BY Ry
// TODO: source = nan, result = denormal
UML_MOV(block, I1, REG(rx));
@@ -4377,6 +4644,36 @@ void adsp21062_device::generate_compute(drcuml_block *block, compiler_state *com
UML_ICOPYFS(block, REG(rn), F4);
return;
+ case 0xe3: // Fn = CLIP Fx BY Fy
+ {
+ code_label label_1 = compiler->labelnum++;
+ code_label label_2 = compiler->labelnum++;
+ UML_FSCOPYI(block, F0, REG(rx));
+ UML_FSCOPYI(block, F1, REG(ry));
+ UML_FSABS(block, F1, F1);
+ UML_FSCMP(block, F0, F1);
+ UML_JMPc(block, COND_C, label_1);
+
+ UML_FSCMP(block, F0, mem(&m_core->fp0));
+ UML_JMPc(block, COND_C, label_2);
+ UML_FSMOV(block, F0, F1);
+ UML_JMP(block, label_1);
+ UML_LABEL(block, label_2);
+ UML_FSNEG(block, F0, F1);
+
+ UML_LABEL(block, label_1);
+ if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED)
+ UML_FSCMP(block, F0, mem(&m_core->fp0));
+ if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ);
+ if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN);
+ if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0);
+ if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0);
+ if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0);
+ if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO
+ UML_ICOPYFS(block, REG(rn), F0);
+ return;
+ }
+
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
{
@@ -5162,8 +5459,7 @@ void adsp21062_device::generate_shift_imm(drcuml_block *block, compiler_state *c
int len = (data >> 6) & 0x3f;
switch (shiftop)
- {
- case 0x01: // ASHIFT Rx BY <data8>
+ {
case 0x11: // FDEP Rx BY <bit6>:<len6>
case 0x13: // FDEP Rx BY <bit6>:<len6> (SE)
case 0x1b: // Rn = Rn OR FDEP Rx BY <bit6>:<len6> (SE)
@@ -5193,6 +5489,29 @@ void adsp21062_device::generate_shift_imm(drcuml_block *block, compiler_state *c
}
return;
+ case 0x01: // ASHIFT Rx BY <data8>
+ if (abs(shift) >= 32)
+ {
+ UML_MOV(block, REG(rn), 0);
+ UML_TEST(block, REG(rn), 0x80000000);
+ UML_MOVc(block, COND_NZ, REG(rn), 0xffffffff);
+ if (SZ_CALC_REQUIRED) UML_MOV(block, ASTAT_SZ, 1);
+ if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 1);
+ if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
+ }
+ else
+ {
+ if (shift < 0)
+ UML_SAR(block, REG(rn), REG(rx), -shift);
+ else
+ UML_SHL(block, REG(rn), REG(rx), shift);
+ if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ);
+ if (SV_CALC_REQUIRED && shift != 0) UML_MOV(block, ASTAT_SV, 1);
+ if (SV_CALC_REQUIRED && shift == 0) UML_MOV(block, ASTAT_SV, 0);
+ if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0);
+ }
+ return;
+
case 0x02: // ROT Rx BY <data8>
if (shift < 0)
UML_ROR(block, REG(rn), REG(rx), (-shift) & 0x1f);