eden/externals/dynarmic/src/dynarmic/backend/arm64/abi.cpp
lizzie 111f2c3be5
[dynarmic] remove mcl/assert.h and mcl/stdint.h (depends on #81) (#89)
Co-authored-by: crueter <crueter@crueter.xyz>
Reviewed-on: eden-emu/eden#89
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-07-25 02:22:38 +02:00

94 lines
3.4 KiB
C++

// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/backend/arm64/abi.h"
#include <vector>
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/common/common_types.h"
#include <oaknut/oaknut.hpp>
namespace Dynarmic::Backend::Arm64 {
using namespace oaknut::util;
static constexpr size_t gpr_size = 8;
static constexpr size_t fpr_size = 16;
struct FrameInfo {
std::vector<int> gprs;
std::vector<int> fprs;
size_t frame_size;
size_t gprs_size;
size_t fprs_size;
};
static std::vector<int> ListToIndexes(u32 list) {
std::vector<int> indexes;
for (int i = 0; i < 32; i++) {
if (mcl::bit::get_bit(i, list)) {
indexes.push_back(i);
}
}
return indexes;
}
static FrameInfo CalculateFrameInfo(RegisterList rl, size_t frame_size) {
const auto gprs = ListToIndexes(static_cast<u32>(rl));
const auto fprs = ListToIndexes(static_cast<u32>(rl >> 32));
const size_t num_gprs = gprs.size();
const size_t num_fprs = fprs.size();
const size_t gprs_size = (num_gprs + 1) / 2 * 16;
const size_t fprs_size = num_fprs * 16;
return {
gprs,
fprs,
frame_size,
gprs_size,
fprs_size,
};
}
#define DO_IT(TYPE, REG_TYPE, PAIR_OP, SINGLE_OP, OFFSET) \
if (frame_info.TYPE##s.size() > 0) { \
for (size_t i = 0; i < frame_info.TYPE##s.size() - 1; i += 2) { \
code.PAIR_OP(oaknut::REG_TYPE{frame_info.TYPE##s[i]}, oaknut::REG_TYPE{frame_info.TYPE##s[i + 1]}, SP, (OFFSET) + i * TYPE##_size); \
} \
if (frame_info.TYPE##s.size() % 2 == 1) { \
const size_t i = frame_info.TYPE##s.size() - 1; \
code.SINGLE_OP(oaknut::REG_TYPE{frame_info.TYPE##s[i]}, SP, (OFFSET) + i * TYPE##_size); \
} \
}
void ABI_PushRegisters(oaknut::CodeGenerator& code, RegisterList rl, size_t frame_size) {
const FrameInfo frame_info = CalculateFrameInfo(rl, frame_size);
code.SUB(SP, SP, frame_info.gprs_size + frame_info.fprs_size);
DO_IT(gpr, XReg, STP, STR, 0)
DO_IT(fpr, QReg, STP, STR, frame_info.gprs_size)
code.SUB(SP, SP, frame_info.frame_size);
}
void ABI_PopRegisters(oaknut::CodeGenerator& code, RegisterList rl, size_t frame_size) {
const FrameInfo frame_info = CalculateFrameInfo(rl, frame_size);
code.ADD(SP, SP, frame_info.frame_size);
DO_IT(gpr, XReg, LDP, LDR, 0)
DO_IT(fpr, QReg, LDP, LDR, frame_info.gprs_size)
code.ADD(SP, SP, frame_info.gprs_size + frame_info.fprs_size);
}
} // namespace Dynarmic::Backend::Arm64