From c1a0f46ea811929b97d37a9fc78148681503e813 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sun, 17 May 2015 16:40:38 -0700 Subject: [PATCH] Implementing dcbz. --- src/xenia/cpu/backend/x64/x64_sequences.cc | 44 ++++++++++++++ src/xenia/cpu/backend/x64/x64_tracers.cc | 12 +++- src/xenia/cpu/backend/x64/x64_tracers.h | 3 + src/xenia/cpu/frontend/ppc_emit_memory.cc | 21 +++++-- src/xenia/cpu/hir/hir_builder.cc | 71 ++++++++++++++-------- src/xenia/cpu/hir/hir_builder.h | 1 + src/xenia/cpu/hir/opcodes.h | 1 + src/xenia/cpu/hir/opcodes.inl | 6 ++ src/xenia/kernel/xboxkrnl_memory.cc | 1 - src/xenia/memory.cc | 11 ++-- 10 files changed, 132 insertions(+), 39 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_sequences.cc b/src/xenia/cpu/backend/x64/x64_sequences.cc index fd3c09e98..60410d248 100644 --- a/src/xenia/cpu/backend/x64/x64_sequences.cc +++ b/src/xenia/cpu/backend/x64/x64_sequences.cc @@ -1673,6 +1673,49 @@ EMITTER_OPCODE_TABLE( PREFETCH); +// ============================================================================ +// OPCODE_MEMSET +// ============================================================================ +EMITTER(MEMSET_I64_I8_I64, MATCH(I, I8<>, I64<>>)) { + static void Emit(X64Emitter& e, const EmitArgType& i) { + assert_true(i.src2.is_constant); + assert_true(i.src3.is_constant); + assert_true(i.src2.constant() == 0); + e.vpxor(e.xmm0, e.xmm0); + auto addr = ComputeMemoryAddress(e, i.src1); + switch (i.src3.constant()) { + case 32: + e.vmovaps(e.ptr[addr + 0 * 16], e.xmm0); + e.vmovaps(e.ptr[addr + 1 * 16], e.xmm0); + break; + case 128: + e.vmovaps(e.ptr[addr + 0 * 16], e.xmm0); + e.vmovaps(e.ptr[addr + 1 * 16], e.xmm0); + e.vmovaps(e.ptr[addr + 2 * 16], e.xmm0); + e.vmovaps(e.ptr[addr + 3 * 16], e.xmm0); + e.vmovaps(e.ptr[addr + 4 * 16], e.xmm0); + e.vmovaps(e.ptr[addr + 5 * 16], e.xmm0); + e.vmovaps(e.ptr[addr + 6 * 16], e.xmm0); + e.vmovaps(e.ptr[addr + 7 * 16], e.xmm0); + break; + default: + assert_unhandled_case(i.src3.constant()); + break; + } + if (IsTracingData()) { + addr = ComputeMemoryAddress(e, i.src1); + e.mov(e.r9, i.src3.constant()); + e.mov(e.r8, i.src2.constant()); + e.lea(e.rdx, e.ptr[addr]); + e.CallNative(reinterpret_cast(TraceMemset)); + } + } +}; +EMITTER_OPCODE_TABLE( + OPCODE_MEMSET, + MEMSET_I64_I8_I64); + + // ============================================================================ // OPCODE_MAX // ============================================================================ @@ -6335,6 +6378,7 @@ void RegisterSequences() { REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE_CONTEXT); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_LOAD); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE); + REGISTER_EMITTER_OPCODE_TABLE(OPCODE_MEMSET); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_PREFETCH); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_MAX); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_MAX); diff --git a/src/xenia/cpu/backend/x64/x64_tracers.cc b/src/xenia/cpu/backend/x64/x64_tracers.cc index e6e250a7c..e3da7a440 100644 --- a/src/xenia/cpu/backend/x64/x64_tracers.cc +++ b/src/xenia/cpu/backend/x64/x64_tracers.cc @@ -28,10 +28,11 @@ namespace x64 { #define TARGET_THREAD 1 -#define IFLUSH() fflush(stdout) +#define IFLUSH() \ + if (thread_state->thread_id() == TARGET_THREAD) fflush(stdout) #define IPRINT \ if (thread_state->thread_id() == TARGET_THREAD) printf -#define DFLUSH() fflush(stdout) +#define DFLUSH() IFLUSH() #define DPRINT \ DFLUSH(); \ if (thread_state->thread_id() == TARGET_THREAD) printf @@ -194,6 +195,13 @@ void TraceMemoryStoreV128(void* raw_context, uint32_t address, __m128 value) { xe::m128_i32<3>(value)); } +void TraceMemset(void* raw_context, uint32_t address, uint8_t value, + uint32_t length) { + auto thread_state = *((ThreadState**)raw_context); + DPRINT("memset %.8X-%.8X (%d) = %.2X", address, address + length, length, + value); +} + } // namespace x64 } // namespace backend } // namespace cpu diff --git a/src/xenia/cpu/backend/x64/x64_tracers.h b/src/xenia/cpu/backend/x64/x64_tracers.h index 1642f7920..c53b7b51d 100644 --- a/src/xenia/cpu/backend/x64/x64_tracers.h +++ b/src/xenia/cpu/backend/x64/x64_tracers.h @@ -64,6 +64,9 @@ void TraceMemoryStoreF32(void* raw_context, uint32_t address, __m128 value); void TraceMemoryStoreF64(void* raw_context, uint32_t address, __m128 value); void TraceMemoryStoreV128(void* raw_context, uint32_t address, __m128 value); +void TraceMemset(void* raw_context, uint32_t address, uint8_t value, + uint32_t length); + } // namespace x64 } // namespace backend } // namespace cpu diff --git a/src/xenia/cpu/frontend/ppc_emit_memory.cc b/src/xenia/cpu/frontend/ppc_emit_memory.cc index cf83bd736..38ef567e3 100644 --- a/src/xenia/cpu/frontend/ppc_emit_memory.cc +++ b/src/xenia/cpu/frontend/ppc_emit_memory.cc @@ -984,11 +984,24 @@ XEEMITTER(dcbtst, 0x7C0001EC, X)(PPCHIRBuilder& f, InstrData& i) { } XEEMITTER(dcbz, 0x7C0007EC, X)(PPCHIRBuilder& f, InstrData& i) { - // No-op for now. - // TODO(benvanik): use prefetch // or dcbz128 0x7C2007EC - // XEINSTRNOTIMPLEMENTED(); - f.Nop(); + // EA <- (RA) + (RB) + // memset(EA & ~31, 0, 32) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + int block_size; + int address_mask; + if (i.X.RT == 1) { + // dcbz128 - 128 byte set + block_size = 128; + address_mask = ~127; + } + else { + // dcbz - 32 byte set + block_size = 32; + address_mask = ~31; + } + f.Memset(f.And(ea, f.LoadConstant(int64_t(address_mask))), + f.LoadZero(INT8_TYPE), f.LoadConstant(int64_t(block_size))); return 0; } diff --git a/src/xenia/cpu/hir/hir_builder.cc b/src/xenia/cpu/hir/hir_builder.cc index f98d81331..dd81767b5 100644 --- a/src/xenia/cpu/hir/hir_builder.cc +++ b/src/xenia/cpu/hir/hir_builder.cc @@ -20,15 +20,27 @@ namespace xe { namespace cpu { namespace hir { -#define ASSERT_ADDRESS_TYPE(value) -#define ASSERT_INTEGER_TYPE(value) -#define ASSERT_FLOAT_TYPE(value) -#define ASSERT_NON_VECTOR_TYPE(value) -#define ASSERT_VECTOR_TYPE(value) +#define ASSERT_ADDRESS_TYPE(value) \ + \ +assert_true((value->type) == INT32_TYPE || (value->type) == INT64_TYPE) +#define ASSERT_INTEGER_TYPE(value) \ + \ +assert_true((value->type) == INT8_TYPE || (value->type) == INT16_TYPE || \ + (value->type) == INT32_TYPE || (value->type) == INT64_TYPE) +#define ASSERT_FLOAT_TYPE(value) \ + assert_true((value->type) == FLOAT32_TYPE || (value->type) == FLOAT64_TYPE) +#define ASSERT_NON_FLOAT_TYPE(value) \ + \ +assert_true((value->type) != FLOAT32_TYPE && (value->type) != FLOAT64_TYPE) +#define ASSERT_NON_VECTOR_TYPE(value) assert_false((value->type) == VEC128_TYPE) +#define ASSERT_VECTOR_TYPE(value) assert_true((value->type) == VEC128_TYPE) +#define ASSERT_FLOAT_OR_VECTOR_TYPE(value) \ + assert_true((value->type) == FLOAT32_TYPE || \ + (value->type) == FLOAT64_TYPE || (value->type) == VEC128_TYPE) #define ASSERT_TYPES_EQUAL(value1, value2) \ assert_true((value1->type) == (value2->type)) -HIRBuilder::HIRBuilder() { + HIRBuilder::HIRBuilder() { arena_ = new Arena(); Reset(); } @@ -755,7 +767,7 @@ void HIRBuilder::ReturnTrue(Value* cond) { return; } - ASSERT_ADDRESS_TYPE(value); + ASSERT_ADDRESS_TYPE(cond); Instr* i = AppendInstr(OPCODE_RETURN_TRUE_info, 0); i->set_src1(cond); i->src2.value = i->src3.value = NULL; @@ -873,8 +885,9 @@ Value* HIRBuilder::SignExtend(Value* value, TypeName target_type) { } Value* HIRBuilder::Truncate(Value* value, TypeName target_type) { - ASSERT_INTEGER_TYPE(value->type); - ASSERT_INTEGER_TYPE(target_type); + ASSERT_INTEGER_TYPE(value); + assert_true(target_type == INT8_TYPE || target_type == INT16_TYPE || + target_type == INT32_TYPE || target_type == INT64_TYPE); if (value->type == target_type) { return value; @@ -908,7 +921,7 @@ Value* HIRBuilder::Convert(Value* value, TypeName target_type, } Value* HIRBuilder::Round(Value* value, RoundMode round_mode) { - ASSERT_FLOAT_TYPE(value); + ASSERT_FLOAT_OR_VECTOR_TYPE(value); if (value->IsConstant()) { Value* dest = CloneValue(value); @@ -1090,6 +1103,16 @@ void HIRBuilder::Store(Value* address, Value* value, uint32_t store_flags) { i->src3.value = NULL; } +void HIRBuilder::Memset(Value* address, Value* value, Value* length) { + ASSERT_ADDRESS_TYPE(address); + ASSERT_TYPES_EQUAL(address, length); + assert_true(value->type == INT8_TYPE); + Instr* i = AppendInstr(OPCODE_MEMSET_info, 0); + i->set_src1(address); + i->set_src2(value); + i->set_src3(length); +} + void HIRBuilder::Prefetch(Value* address, size_t length, uint32_t prefetch_flags) { ASSERT_ADDRESS_TYPE(address); @@ -1471,8 +1494,6 @@ Value* HIRBuilder::MulSub(Value* value1, Value* value2, Value* value3) { } Value* HIRBuilder::Neg(Value* value) { - ASSERT_NON_VECTOR_TYPE(value); - Instr* i = AppendInstr(OPCODE_NEG_info, 0, AllocValue(value->type)); i->set_src1(value); i->src2.value = i->src3.value = NULL; @@ -1480,7 +1501,7 @@ Value* HIRBuilder::Neg(Value* value) { } Value* HIRBuilder::Abs(Value* value) { - ASSERT_NON_VECTOR_TYPE(value); + ASSERT_FLOAT_OR_VECTOR_TYPE(value); Instr* i = AppendInstr(OPCODE_ABS_info, 0, AllocValue(value->type)); i->set_src1(value); @@ -1489,7 +1510,7 @@ Value* HIRBuilder::Abs(Value* value) { } Value* HIRBuilder::Sqrt(Value* value) { - ASSERT_FLOAT_TYPE(value); + ASSERT_FLOAT_OR_VECTOR_TYPE(value); Instr* i = AppendInstr(OPCODE_SQRT_info, 0, AllocValue(value->type)); i->set_src1(value); @@ -1498,7 +1519,7 @@ Value* HIRBuilder::Sqrt(Value* value) { } Value* HIRBuilder::RSqrt(Value* value) { - ASSERT_FLOAT_TYPE(value); + ASSERT_FLOAT_OR_VECTOR_TYPE(value); Instr* i = AppendInstr(OPCODE_RSQRT_info, 0, AllocValue(value->type)); i->set_src1(value); @@ -1507,7 +1528,7 @@ Value* HIRBuilder::RSqrt(Value* value) { } Value* HIRBuilder::Pow2(Value* value) { - ASSERT_FLOAT_TYPE(value); + ASSERT_FLOAT_OR_VECTOR_TYPE(value); Instr* i = AppendInstr(OPCODE_POW2_info, 0, AllocValue(value->type)); i->set_src1(value); @@ -1516,7 +1537,7 @@ Value* HIRBuilder::Pow2(Value* value) { } Value* HIRBuilder::Log2(Value* value) { - ASSERT_FLOAT_TYPE(value); + ASSERT_FLOAT_OR_VECTOR_TYPE(value); Instr* i = AppendInstr(OPCODE_LOG2_info, 0, AllocValue(value->type)); i->set_src1(value); @@ -1551,8 +1572,8 @@ Value* HIRBuilder::DotProduct4(Value* value1, Value* value2) { } Value* HIRBuilder::And(Value* value1, Value* value2) { - ASSERT_INTEGER_TYPE(value1); - ASSERT_INTEGER_TYPE(value2); + ASSERT_NON_FLOAT_TYPE(value1); + ASSERT_NON_FLOAT_TYPE(value2); ASSERT_TYPES_EQUAL(value1, value2); if (value1 == value2) { @@ -1571,8 +1592,8 @@ Value* HIRBuilder::And(Value* value1, Value* value2) { } Value* HIRBuilder::Or(Value* value1, Value* value2) { - ASSERT_INTEGER_TYPE(value1); - ASSERT_INTEGER_TYPE(value2); + ASSERT_NON_FLOAT_TYPE(value1); + ASSERT_NON_FLOAT_TYPE(value2); ASSERT_TYPES_EQUAL(value1, value2); if (value1 == value2) { @@ -1591,8 +1612,8 @@ Value* HIRBuilder::Or(Value* value1, Value* value2) { } Value* HIRBuilder::Xor(Value* value1, Value* value2) { - ASSERT_INTEGER_TYPE(value1); - ASSERT_INTEGER_TYPE(value2); + ASSERT_NON_FLOAT_TYPE(value1); + ASSERT_NON_FLOAT_TYPE(value2); ASSERT_TYPES_EQUAL(value1, value2); if (value1 == value2) { @@ -1607,7 +1628,7 @@ Value* HIRBuilder::Xor(Value* value1, Value* value2) { } Value* HIRBuilder::Not(Value* value) { - ASSERT_INTEGER_TYPE(value); + ASSERT_NON_FLOAT_TYPE(value); if (value->IsConstant()) { Value* dest = CloneValue(value); @@ -1657,7 +1678,7 @@ Value* HIRBuilder::VectorShl(Value* value1, Value* value2, TypeName part_type) { } Value* HIRBuilder::Shr(Value* value1, Value* value2) { - ASSERT_INTEGER_TYPE(value1); + ASSERT_NON_FLOAT_TYPE(value1); ASSERT_INTEGER_TYPE(value2); if (value2->IsConstantZero()) { diff --git a/src/xenia/cpu/hir/hir_builder.h b/src/xenia/cpu/hir/hir_builder.h index c90eebcf9..e189f65c2 100644 --- a/src/xenia/cpu/hir/hir_builder.h +++ b/src/xenia/cpu/hir/hir_builder.h @@ -132,6 +132,7 @@ class HIRBuilder { Value* Load(Value* address, TypeName type, uint32_t load_flags = 0); void Store(Value* address, Value* value, uint32_t store_flags = 0); + void Memset(Value* address, Value* value, Value* length); void Prefetch(Value* address, size_t length, uint32_t prefetch_flags = 0); Value* Max(Value* value1, Value* value2); diff --git a/src/xenia/cpu/hir/opcodes.h b/src/xenia/cpu/hir/opcodes.h index 609a990a9..e904903a2 100644 --- a/src/xenia/cpu/hir/opcodes.h +++ b/src/xenia/cpu/hir/opcodes.h @@ -142,6 +142,7 @@ enum Opcode { OPCODE_STORE_CONTEXT, OPCODE_LOAD, OPCODE_STORE, + OPCODE_MEMSET, OPCODE_PREFETCH, OPCODE_MAX, OPCODE_VECTOR_MAX, diff --git a/src/xenia/cpu/hir/opcodes.inl b/src/xenia/cpu/hir/opcodes.inl index 4a6b2a3f7..a023e21e2 100644 --- a/src/xenia/cpu/hir/opcodes.inl +++ b/src/xenia/cpu/hir/opcodes.inl @@ -224,6 +224,12 @@ DEFINE_OPCODE( OPCODE_SIG_X_V_V, OPCODE_FLAG_MEMORY) +DEFINE_OPCODE( + OPCODE_MEMSET, + "memset", + OPCODE_SIG_X_V_V_V, + 0) + DEFINE_OPCODE( OPCODE_PREFETCH, "prefetch", diff --git a/src/xenia/kernel/xboxkrnl_memory.cc b/src/xenia/kernel/xboxkrnl_memory.cc index a1855c20f..639d8d3a4 100644 --- a/src/xenia/kernel/xboxkrnl_memory.cc +++ b/src/xenia/kernel/xboxkrnl_memory.cc @@ -323,7 +323,6 @@ SHIM_CALL MmAllocatePhysicalMemoryEx_shim(PPCContext* ppc_state, } XELOGD("MmAllocatePhysicalMemoryEx = %.8X", base_address); - SHIM_SET_RETURN_64(base_address); } diff --git a/src/xenia/memory.cc b/src/xenia/memory.cc index dfa7471a0..606f69e2f 100644 --- a/src/xenia/memory.cc +++ b/src/xenia/memory.cc @@ -191,13 +191,10 @@ int Memory::Initialize() { return 1; } - // I have no idea what this is, but games try to read/write there. - heaps_.v40000000.AllocFixed( - 0x40000000, 0x00010000, 32, - kMemoryAllocationReserve | kMemoryAllocationCommit, - kMemoryProtectRead | kMemoryProtectWrite); - xe::store_and_swap(TranslateVirtual(0x40000000), 0x00C40000); - xe::store_and_swap(TranslateVirtual(0x40000004), 0x00010000); + // ? + uint32_t unk_phys_alloc; + heaps_.vA0000000.Alloc(0x340000, 64 * 1024, kMemoryAllocationReserve, + kMemoryProtectNoAccess, true, &unk_phys_alloc); return 0; }