summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author angelosa <lordkale4@gmail.com>2019-09-11 05:39:56 +0200
committer angelosa <lordkale4@gmail.com>2019-09-11 05:39:56 +0200
commit18946a88e76bd6b04c1910050b55a9a5c2136a7f (patch)
tree2a32887da2e67c4394d9c0d133e180aa32441180
parent0e4d54c5087f1e2b4e8bf98bc181e22597a9d99b (diff)
Added some COPRO opcodes, Sim City enters into gameplay
-rw-r--r--src/devices/cpu/arm/arm.cpp181
-rw-r--r--src/devices/cpu/arm/arm.h10
2 files changed, 182 insertions, 9 deletions
diff --git a/src/devices/cpu/arm/arm.cpp b/src/devices/cpu/arm/arm.cpp
index 2e3ded89dfb..5d1431be7d5 100644
--- a/src/devices/cpu/arm/arm.cpp
+++ b/src/devices/cpu/arm/arm.cpp
@@ -326,6 +326,10 @@ void arm_cpu_device::device_reset()
{
elem = 0;
}
+ for (auto & elem : m_coproControl)
+ {
+ elem = 0;
+ }
m_pendingIrq = 0;
m_pendingFiq = 0;
@@ -507,6 +511,7 @@ void arm_cpu_device::device_start()
save_item(NAME(m_sArmRegister));
save_item(NAME(m_coproRegister));
+ save_item(NAME(m_coproControl));
save_item(NAME(m_pendingIrq));
save_item(NAME(m_pendingFiq));
@@ -538,6 +543,17 @@ void arm_cpu_device::device_start()
state_add( ARM32_IR14, "IR14", m_sArmRegister[eR14_IRQ] ).formatstr("%08X");
state_add( ARM32_SR13, "SR13", m_sArmRegister[eR13_SVC] ).formatstr("%08X");
state_add( ARM32_SR14, "SR14", m_sArmRegister[eR14_SVC] ).formatstr("%08X");
+ if (m_copro_type == copro_type::VL86C020)
+ {
+ state_add( COPRO_F0, "F0", m_coproRegister[0] ).formatstr("%08X");
+ state_add( COPRO_F1, "F1", m_coproRegister[1] ).formatstr("%08X");
+ state_add( COPRO_F2, "F2", m_coproRegister[2] ).formatstr("%08X");
+ state_add( COPRO_F3, "F3", m_coproRegister[3] ).formatstr("%08X");
+ state_add( COPRO_F4, "F4", m_coproRegister[4] ).formatstr("%08X");
+ state_add( COPRO_F5, "F5", m_coproRegister[5] ).formatstr("%08X");
+ state_add( COPRO_F6, "F6", m_coproRegister[6] ).formatstr("%08X");
+ state_add( COPRO_F7, "F7", m_coproRegister[7] ).formatstr("%08X");
+ }
state_add(STATE_GENPC, "GENPC", m_sArmRegister[15]).mask(ADDRESS_MASK).formatstr("%8s").noshow();
state_add(STATE_GENPCBASE, "CURPC", m_sArmRegister[15]).mask(ADDRESS_MASK).formatstr("%8s").noshow();
@@ -1419,15 +1435,165 @@ uint32_t arm_cpu_device::DecimalToBCD(uint32_t value)
return accumulator;
}
+inline float32_t arm_cpu_device::ReadCoProRegOrConst32(const uint32_t idx)
+{
+ if (idx & 8)
+ {
+ float32_t table[8] = { 0x00000000, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x3f000000, 0x41200000 };
+ return table[idx & 7];
+ }
+
+ return ui32_to_f32(m_coproRegister[idx]);
+}
+
+inline float64_t arm_cpu_device::ReadCoProRegOrConst64(const uint32_t idx)
+{
+ if (idx & 8)
+ {
+ float64_t table[8] = { 0x0000000000000000, 0x3ff0000000000000, 0x4000000000000000, 0x4008000000000000,
+ 0x4010000000000000, 0x4014000000000000, 0x3fe0000000000000, 0x4024000000000000 };
+ return table[idx & 7];
+ }
+
+ return ui32_to_f64(m_coproRegister[idx]);
+}
+
+
void arm_cpu_device::HandleCoProVL86C020( uint32_t insn )
{
- uint32_t rn=(insn>>12)&0xf;
- uint32_t crn=(insn>>16)&0xf;
+ uint32_t rn = (insn>>12)&0xf;
+ uint32_t crn = (insn>>16)&0x7;
+ uint32_t crn2 = insn & 0xf;
+ // nearest, Plus infinity, Minus infinity, Zero
+ const uint_fast8_t arm_to_sf_rounding[4] = {
+ softfloat_round_near_even,
+ softfloat_round_max,
+ softfloat_round_min,
+ softfloat_round_near_maxMag
+ };
+ uint8_t round_mode = arm_to_sf_rounding[(insn>>5)&0x3];
+ // Single, Double, double Extended, Packed decimal
+ uint8_t precision_mode = (BIT(insn,20)<<1)|(BIT(insn,7));
m_icount -= S_CYCLE;
+ if (precision_mode >= 2)
+ {
+ //printf("%08x: Unimplemented VL86C020 copro precision mode %08x %d %d\n", R15 & 0x3ffffff, insn,rn,crn);
+ return;
+ }
+
+ // FLT - integer to floating point reg
+ if((insn & 0x0ff00f1f) == 0x0e000110)
+ {
+ m_coproRegister[crn] = GetRegister(rn);
+ }
+ // FIX - floating point to integer reg
+ else if ((insn & 0x0fff0f98) == 0x0e100110)
+ {
+ uint32_t result;
+ switch(precision_mode)
+ {
+ case 0:
+ {
+ float32_t src = ui32_to_f32(m_coproRegister[crn]);
+ result = f32_to_ui32(src, round_mode, true);
+ break;
+ }
+ case 1:
+ {
+ float64_t src = ui32_to_f64(m_coproRegister[crn]);
+ result = f64_to_ui32(src, round_mode, true);
+ break;
+ }
+ }
+
+ SetRegister(rn, result);
+ }
+ // ADF - Addition between floating point regs
+ else if ((insn&0x0ff08f10)==0x0e000100 )
+ {
+ uint32_t result;
+ rn &= 7;
+ switch(precision_mode)
+ {
+ case 0:
+ {
+ float32_t op1 = ui32_to_f32(m_coproRegister[crn]);
+ float32_t op2 = ReadCoProRegOrConst32(crn2);
+ float32_t fres = f32_add(op1, op2);
+ result = f32_to_ui32(fres, round_mode, true);
+ break;
+ }
+ case 1:
+ {
+ float64_t op1 = ui32_to_f64(m_coproRegister[crn]);
+ float64_t op2 = ReadCoProRegOrConst64(crn2);
+ float64_t fres = f64_add(op1, op2);
+ result = f64_to_ui32(fres, round_mode, true);
+ break;
+ }
+ }
+
+ m_coproRegister[rn] = result;
+ }
+ // MVF - Move
+ else if ( (insn&0x0ff08f10)==0x0e008100 )
+ {
+ uint32_t result;
+
+ switch(precision_mode)
+ {
+ case 0:
+ {
+ float32_t fres = ReadCoProRegOrConst32(crn2);
+ result = f32_to_ui32(fres, round_mode, true);
+ break;
+ }
+ case 1:
+ {
+ float64_t fres = ReadCoProRegOrConst64(crn2);
+ result = f64_to_ui32(fres, round_mode, true);
+ break;
+ }
+ }
+
+ m_coproRegister[crn] = result;
+ }
+ // CMFS - compare
+ else if ( (insn&0x0ff8fff0) == 0x0e90f110)
+ {
+ bool result;
+
+ // TODO: according to "The Hacker" on AA, op2 ignores constants here, needs to be counterchecked.
+ switch(precision_mode)
+ {
+ case 0:
+ {
+ float32_t op1 = ui32_to_f32(m_coproRegister[crn]);
+ float32_t op2 = ui32_to_f32(m_coproRegister[crn2 & 7]);
+ result = f32_eq(op1, op2);
+ break;
+ }
+ case 1:
+ {
+ float64_t op1 = ui32_to_f64(m_coproRegister[crn]);
+ float64_t op2 = ui32_to_f64(m_coproRegister[crn2 & 7]);
+ result = f64_eq(op1, op2);
+ break;
+ }
+ }
+
+ if (result == true)
+ R15 |= (Z_MASK);
+ else
+ R15 &= ~(Z_MASK);
+
+ // TODO: V flag
+ R15 &= ~(V_MASK);
+ }
/* MRC - transfer copro register to main register */
- if( (insn&0x0f100010)==0x0e100010 )
+ else if( (insn&0x0f100010)==0x0e100010 )
{
if(crn == 0) // ID, read only
{
@@ -1440,16 +1606,17 @@ void arm_cpu_device::HandleCoProVL86C020( uint32_t insn )
SetRegister(rn, 0x41560300);
//machine().debug_break();
}
- else
- SetRegister(rn, m_coproRegister[crn]);
+ else if (crn >= 2 && crn < 6)
+ SetRegister(rn, m_coproControl[crn]);
}
/* MCR - transfer main register to copro register */
else if( (insn&0x0f100010)==0x0e000010 )
{
- if(crn != 0)
- m_coproRegister[crn]=GetRegister(rn);
+ if(crn >= 2 && crn < 6)
+ m_coproControl[crn]=GetRegister(rn);
+ // TODO: cache, trap if accessed in user mode, undefined instruction trap if any illegal access occurs (probably)
//printf("%08x: VL86C020 copro instruction write %08x %d %d\n", R15 & 0x3ffffff, insn,rn,crn);
}
else
diff --git a/src/devices/cpu/arm/arm.h b/src/devices/cpu/arm/arm.h
index 27f764e26df..c81bde20e8a 100644
--- a/src/devices/cpu/arm/arm.h
+++ b/src/devices/cpu/arm/arm.h
@@ -6,6 +6,8 @@
#pragma once
+#include "softfloat3/source/include/softfloat.h"
+
/****************************************************************************************************
* INTERRUPT CONSTANTS
***************************************************************************************************/
@@ -38,7 +40,8 @@ protected:
ARM32_R0, ARM32_R1, ARM32_R2, ARM32_R3, ARM32_R4, ARM32_R5, ARM32_R6, ARM32_R7,
ARM32_R8, ARM32_R9, ARM32_R10, ARM32_R11, ARM32_R12, ARM32_R13, ARM32_R14, ARM32_R15,
ARM32_FR8, ARM32_FR9, ARM32_FR10, ARM32_FR11, ARM32_FR12, ARM32_FR13, ARM32_FR14,
- ARM32_IR13, ARM32_IR14, ARM32_SR13, ARM32_SR14
+ ARM32_IR13, ARM32_IR14, ARM32_SR13, ARM32_SR14,
+ COPRO_F0, COPRO_F1, COPRO_F2, COPRO_F3, COPRO_F4, COPRO_F5, COPRO_F6, COPRO_F7
};
arm_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness);
@@ -67,7 +70,8 @@ protected:
int m_icount;
uint32_t m_sArmRegister[27];
- uint32_t m_coproRegister[16];
+ u32 m_coproRegister[16];
+ uint32_t m_coproControl[16];
uint8_t m_pendingIrq;
uint8_t m_pendingFiq;
address_space *m_program;
@@ -98,6 +102,8 @@ protected:
int storeDec(uint32_t pat, uint32_t rbv);
static uint32_t BCDToDecimal(uint32_t value);
static uint32_t DecimalToBCD(uint32_t value);
+ inline float32_t ReadCoProRegOrConst32(uint32_t idx);
+ inline float64_t ReadCoProRegOrConst64(uint32_t idx);
};