Compare commits
3
Commits
de6e324bde
...
cf0378719c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf0378719c | ||
|
|
642fc17391 | ||
|
|
00cc9309cb |
Vendored
+26
-26
@@ -1,43 +1,43 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <types.hpp>
|
#include <ircolib/types.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace ircolib {
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace ircolib {
|
static inline std::vector<u8> read_file_binary(const std::string &path) {
|
||||||
static inline std::vector<u8> ReadFileBinary(const std::string &path) {
|
std::ifstream file(path, std::ios::binary);
|
||||||
std::ifstream file(path, std::ios::binary);
|
return {std::istreambuf_iterator{file}, {}};
|
||||||
return {std::istreambuf_iterator{file}, {}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void WriteFileBinary(const std::vector<u8> &data, const std::string &path) {
|
static inline void write_file_binary(const std::vector<u8> &data, const std::string &path) {
|
||||||
std::ofstream file(path, std::ios::binary);
|
std::ofstream file(path, std::ios::binary);
|
||||||
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
|
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void WriteFileBinary(const u8 *data, const size_t size, const std::string &path) {
|
static inline void write_file_binary(const u8 *data, const u32 size, const std::string &path) {
|
||||||
FILE *out = fopen(path.c_str(), "wb");
|
FILE *out = fopen(path.c_str(), "wb");
|
||||||
fwrite(data, size, 1, out);
|
fwrite(data, size, 1, out);
|
||||||
fclose(out);
|
fclose(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Size>
|
template <size_t Size>
|
||||||
static inline void WriteFileBinary(const std::array<u8, Size> &data, const std::string &path) {
|
static inline void write_file_binary(const std::array<u8, Size> &data, const std::string &path) {
|
||||||
std::ofstream file(path, std::ios::binary);
|
std::ofstream file(path, std::ios::binary);
|
||||||
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
|
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t NextPow2(size_t num) {
|
static inline u32 next_pow2(u32 num) {
|
||||||
// Taken from "Bit Twiddling Hacks" by Sean Anderson:
|
// Taken from "Bit Twiddling Hacks" by Sean Anderson:
|
||||||
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||||
--num;
|
--num;
|
||||||
num |= num >> 1;
|
num |= num >> 1;
|
||||||
num |= num >> 2;
|
num |= num >> 2;
|
||||||
num |= num >> 4;
|
num |= num >> 4;
|
||||||
num |= num >> 8;
|
num |= num >> 8;
|
||||||
num |= num >> 16;
|
num |= num >> 16;
|
||||||
return num + 1;
|
return num + 1;
|
||||||
}
|
}
|
||||||
} // namespace Util
|
} // namespace ircolib
|
||||||
|
|||||||
Vendored
+42
-43
@@ -1,106 +1,105 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cmath>
|
#include <ircolib/types.hpp>
|
||||||
#include <types.hpp>
|
|
||||||
|
|
||||||
namespace ircolib {
|
namespace ircolib {
|
||||||
static inline auto roundCeil(float f) {
|
static inline auto roundCeil(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128 t = _mm_set_ss(f);
|
__m128 t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_POS_INF);
|
t = _mm_round_ss(t, t, _MM_FROUND_TO_POS_INF);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return ceilf(f);
|
return ceilf(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundCeil(double f) {
|
static inline auto roundCeil(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128d t = _mm_set_sd(f);
|
__m128d t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_POS_INF);
|
t = _mm_round_sd(t, t, _MM_FROUND_TO_POS_INF);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return ceil(f);
|
return ceil(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundNearest(float f) {
|
static inline auto roundNearest(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128 t = _mm_set_ss(f);
|
__m128 t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEAREST_INT);
|
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEAREST_INT);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return roundf(f);
|
return roundf(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundNearest(double f) {
|
static inline auto roundNearest(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128d t = _mm_set_sd(f);
|
__m128d t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEAREST_INT);
|
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEAREST_INT);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return round(f);
|
return round(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundCurrent(float f) {
|
static inline auto roundCurrent(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
auto t = _mm_set_ss(f);
|
auto t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_CUR_DIRECTION);
|
t = _mm_round_ss(t, t, _MM_FROUND_CUR_DIRECTION);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return rint(f);
|
return rint(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundCurrent(double f) {
|
static inline auto roundCurrent(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
auto t = _mm_set_sd(f);
|
auto t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_CUR_DIRECTION);
|
t = _mm_round_sd(t, t, _MM_FROUND_CUR_DIRECTION);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return rint(f);
|
return rint(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline auto roundFloor(float f) {
|
static inline auto roundFloor(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128 t = _mm_set_ss(f);
|
__m128 t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEG_INF);
|
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEG_INF);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return floor(f);
|
return floor(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundFloor(double f) {
|
static inline auto roundFloor(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128d t = _mm_set_sd(f);
|
__m128d t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEG_INF);
|
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEG_INF);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return floor(f);
|
return floor(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundTrunc(float f) {
|
static inline auto roundTrunc(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128 t = _mm_set_ss(f);
|
__m128 t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_ZERO);
|
t = _mm_round_ss(t, t, _MM_FROUND_TO_ZERO);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return trunc(f);
|
return trunc(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundTrunc(double f) {
|
static inline auto roundTrunc(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128d t = _mm_set_sd(f);
|
__m128d t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_ZERO);
|
t = _mm_round_sd(t, t, _MM_FROUND_TO_ZERO);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return trunc(f);
|
return trunc(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace Util
|
} // namespace ircolib
|
||||||
|
|||||||
Vendored
+61
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <print>
|
||||||
|
#include <ircolib/types.hpp>
|
||||||
|
|
||||||
|
namespace ircolib {
|
||||||
|
enum LogLevel : u8 { Trace, Debug, Info, Warn, Error, Always };
|
||||||
|
|
||||||
|
constexpr LogLevel globalLogLevel = Warn;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void panic(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
std::print("[FATAL] ");
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void error(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
if (LogLevel::Error >= globalLogLevel) {
|
||||||
|
std::print("[ERROR] ");
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void warn(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
if (LogLevel::Warn >= globalLogLevel) {
|
||||||
|
std::print("[WARN] ");
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void info(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
if (LogLevel::Info >= globalLogLevel) {
|
||||||
|
std::print("[INFO] ");
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void debug(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
if (LogLevel::Debug >= globalLogLevel) {
|
||||||
|
std::print("[DEBUG] ");
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void trace(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
if (LogLevel::Trace >= globalLogLevel) {
|
||||||
|
std::print("[TRACE] ");
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void always(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
} // namespace ircolib
|
||||||
Vendored
+85
-71
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <types.hpp>
|
#include "types.hpp"
|
||||||
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
@@ -8,139 +9,152 @@
|
|||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
|
||||||
namespace ircolib {
|
namespace ircolib {
|
||||||
static inline std::vector<u8> IntegralToBuffer(const std::integral auto &val) {
|
static inline std::vector<u8> integral_to_buffer(const std::integral auto &val) {
|
||||||
std::vector<u8> ret{};
|
std::vector<u8> ret{};
|
||||||
ret.resize(sizeof(val));
|
ret.resize(sizeof(val));
|
||||||
|
|
||||||
memcpy(ret.data(), &val, sizeof(val));
|
memcpy(ret.data(), &val, sizeof(val));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline constexpr bool IsInsideRange(const std::integral auto& addr,
|
static inline auto integral_to_slice(const std::integral auto &val) -> std::array<u8, sizeof(val)> {
|
||||||
const std::integral auto& start,
|
std::array<u8, sizeof(val)> ret{};
|
||||||
const std::integral auto& end) {
|
|
||||||
return addr >= start && addr <= end;
|
memcpy(ret.data(), &val, sizeof(val));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr bool is_inside_range(const std::integral auto &addr, const std::integral auto &start,
|
||||||
|
const std::integral auto &end) {
|
||||||
|
return addr >= start && addr <= end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline T ReadAccess(const u8 *data, const u32 index);
|
static constexpr inline T read_access(const u8 *data, const u32 index);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline T ReadAccess(const std::vector<u8> &data, const u32 index);
|
static constexpr inline T read_access(const std::vector<u8> &data, const u32 index);
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline T ReadAccess(const std::array<u8, Size> &data, const u32 index);
|
static constexpr inline T read_access(const std::array<u8, Size> &data, const u32 index);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void WriteAccess(u8 *data, const u32 index, const T val);
|
static constexpr inline void write_access(u8 *data, const u32 index, const T val);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void WriteAccess(std::vector<u8> &data, const u32 index, const T val);
|
static constexpr inline void write_access(std::vector<u8> &data, const u32 index, const T val);
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline void WriteAccess(std::array<u8, Size> &data, const u32 index, const T val);
|
static constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const T val);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
constexpr inline u64 ReadAccess(const u8 *data, const u32 index) {
|
constexpr inline u64 read_access(const u8 *data, const u32 index) {
|
||||||
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
||||||
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
||||||
const auto& result = static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
|
const auto &result = static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline T ReadAccess(const u8 *data, const u32 index) {
|
static constexpr inline T read_access(const u8 *data, const u32 index) {
|
||||||
return *reinterpret_cast<const T *>(&data[index]);
|
return *reinterpret_cast<const T *>(&data[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
constexpr inline u64 ReadAccess(const std::vector<u8> &data, const u32 index) {
|
constexpr inline u64 read_access(const std::vector<u8> &data, const u32 index) {
|
||||||
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
||||||
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
||||||
return (static_cast<u64>(hi) << 32) | static_cast<u64>(lo);
|
return (static_cast<u64>(hi) << 32) | static_cast<u64>(lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline T ReadAccess(const std::vector<u8> &data, const u32 index) {
|
static constexpr inline T read_access(const std::vector<u8> &data, const u32 index) {
|
||||||
return *reinterpret_cast<const T *>(&data[index]);
|
return *reinterpret_cast<const T *>(&data[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Size>
|
template <size_t Size>
|
||||||
constexpr inline u64 ReadAccess(const std::array<u8, Size> &data, const u32 index) {
|
static constexpr inline u64 read_access(const std::array<u8, Size> &data, const u32 index) {
|
||||||
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
||||||
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
||||||
return static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
|
return static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline T ReadAccess(const std::array<u8, Size> &data, const u32 index) {
|
static constexpr inline T read_access(const std::array<u8, Size> &data, const u32 index) {
|
||||||
return *reinterpret_cast<const T *>(&data[index]);
|
return *reinterpret_cast<const T *>(&data[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Size>
|
template <size_t Size>
|
||||||
constexpr inline void WriteAccess(std::array<u8, Size> &data, const u32 index, const u64 val) {
|
static constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const u64 val) {
|
||||||
const u32 hi = val >> 32;
|
const u32 hi = val >> 32;
|
||||||
const u32 lo = val;
|
const u32 lo = val;
|
||||||
|
|
||||||
*reinterpret_cast<u32 *>(&data[index + 0]) = hi;
|
*reinterpret_cast<u32 *>(&data[index + 0]) = hi;
|
||||||
*reinterpret_cast<u32 *>(&data[index + 4]) = lo;
|
*reinterpret_cast<u32 *>(&data[index + 4]) = lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline void WriteAccess(std::array<u8, Size> &data, const u32 index, const T val) {
|
static constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const T val) {
|
||||||
*reinterpret_cast<T *>(&data[index]) = val;
|
*reinterpret_cast<T *>(&data[index]) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
constexpr inline void WriteAccess(std::vector<u8> &data, const u32 index, const u64 val) {
|
constexpr inline void write_access(std::vector<u8> &data, const u32 index, const u64 val) {
|
||||||
const u32 hi = val >> 32;
|
const u32 hi = val >> 32;
|
||||||
const u32 lo = val;
|
const u32 lo = val;
|
||||||
|
|
||||||
*reinterpret_cast<u32 *>(&data[index + 0]) = hi;
|
*reinterpret_cast<u32 *>(&data[index + 0]) = hi;
|
||||||
*reinterpret_cast<u32 *>(&data[index + 4]) = lo;
|
*reinterpret_cast<u32 *>(&data[index + 4]) = lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void WriteAccess(std::vector<u8> &data, const u32 index, const T val) {
|
static constexpr inline void write_access(std::vector<u8> &data, const u32 index, const T val) {
|
||||||
*reinterpret_cast<T *>(&data[index]) = val;
|
*reinterpret_cast<T *>(&data[index]) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
constexpr inline void WriteAccess(u8 *data, const u32 index, const u64 val) {
|
constexpr inline void write_access(u8 *data, const u32 index, const u64 val) {
|
||||||
const u32 hi = val >> 32;
|
const u32 hi = val >> 32;
|
||||||
const u32 lo = val;
|
const u32 lo = val;
|
||||||
|
|
||||||
*reinterpret_cast<u32 *>(&data[index + 0]) = hi;
|
*reinterpret_cast<u32 *>(&data[index + 0]) = hi;
|
||||||
*reinterpret_cast<u32 *>(&data[index + 4]) = lo;
|
*reinterpret_cast<u32 *>(&data[index + 4]) = lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void WriteAccess(u8 *data, const u32 index, const T val) {
|
static constexpr inline void write_access(u8 *data, const u32 index, const T val) {
|
||||||
*reinterpret_cast<T *>(&data[index]) = val;
|
*reinterpret_cast<T *>(&data[index]) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void SwapBuffer(std::vector<u8> &data) {
|
static constexpr inline void swap_buffer(std::vector<u8> &data) {
|
||||||
for (size_t i = 0; i < data.size(); i += sizeof(T)) {
|
for (u32 i = 0; i < data.size(); i += sizeof(T)) {
|
||||||
const T original = *reinterpret_cast<T *>(&data[i]);
|
const T original = *reinterpret_cast<T *>(&data[i]);
|
||||||
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline void SwapBuffer(std::array<u8, Size> &data) {
|
static constexpr inline void swap_buffer(std::array<u8, Size> &data) {
|
||||||
for (size_t i = 0; i < data.size(); i += sizeof(T)) {
|
for (u32 i = 0; i < data.size(); i += sizeof(T)) {
|
||||||
const T original = *reinterpret_cast<T *>(&data[i]);
|
const T original = *reinterpret_cast<T *>(&data[i]);
|
||||||
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static constexpr inline void swap_buffer(u8 *data, u32 size) {
|
||||||
|
for (u32 i = 0; i < size; i += sizeof(T)) {
|
||||||
|
const T original = *reinterpret_cast<T *>(&data[i]);
|
||||||
|
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
inline void *aligned_alloc(const size_t alignment, const size_t size) { return _aligned_malloc(size, alignment); }
|
inline void *aligned_alloc(const u32 alignment, const u32 size) { return _aligned_malloc(size, alignment); }
|
||||||
|
|
||||||
inline void aligned_free(void *ptr) { _aligned_free(ptr); }
|
inline void aligned_free(void *ptr) { _aligned_free(ptr); }
|
||||||
#else
|
#else
|
||||||
inline void *aligned_alloc(const size_t alignment, const size_t size) {
|
inline void *aligned_alloc(const u32 alignment, const u32 size) { return std::aligned_alloc(alignment, size); }
|
||||||
return std::aligned_alloc(alignment, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void aligned_free(void *ptr) { std::free(ptr); }
|
inline void aligned_free(void *ptr) { std::free(ptr); }
|
||||||
#endif
|
#endif
|
||||||
} // namespace Util
|
} // namespace ircolib
|
||||||
|
|||||||
Vendored
+36
-1
@@ -1,5 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#ifdef USE_NEON
|
||||||
|
#include <sse2neon.h>
|
||||||
|
#else
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#include <smmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ircolib {
|
namespace ircolib {
|
||||||
using u8 = uint8_t;
|
using u8 = uint8_t;
|
||||||
@@ -10,4 +16,33 @@ using s8 = int8_t;
|
|||||||
using s16 = int16_t;
|
using s16 = int16_t;
|
||||||
using s32 = int32_t;
|
using s32 = int32_t;
|
||||||
using s64 = int64_t;
|
using s64 = int64_t;
|
||||||
}
|
|
||||||
|
template <typename T, u32 bit>
|
||||||
|
static constexpr bool is_bit_set(const T &val) {
|
||||||
|
return val & (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, u32 bit>
|
||||||
|
static constexpr void set_bit(T &val) {
|
||||||
|
val |= 1 << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool is_bit_set(const T &val, const u32 &bit) {
|
||||||
|
return val & (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void set_bit(T &val, const u32 &bit) {
|
||||||
|
val |= 1 << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void clear_bit(T &val, const u32 &bit) {
|
||||||
|
val &= ~(1 << bit);
|
||||||
|
}
|
||||||
|
} // namespace ircolib
|
||||||
|
|
||||||
|
constexpr ircolib::u32 operator""_kib(const unsigned long long v) { return v * 1024; }
|
||||||
|
constexpr ircolib::u32 operator""_mib(const unsigned long long v) { return v * 1024 * 1024; }
|
||||||
|
constexpr ircolib::u32 operator""_gib(const unsigned long long v) { return v * 1024 * 1024 * 1024; }
|
||||||
|
|||||||
+7
-6
@@ -38,7 +38,7 @@ Util::IntrusivePtr<Context> InitVulkanContext(WSIPlatform *platform, const unsig
|
|||||||
|
|
||||||
if (!new_context->init_instance(instance_ext.data(), instance_ext.size(),
|
if (!new_context->init_instance(instance_ext.data(), instance_ext.size(),
|
||||||
CONTEXT_CREATION_ENABLE_ADVANCED_WSI_BIT)) {
|
CONTEXT_CREATION_ENABLE_ADVANCED_WSI_BIT)) {
|
||||||
panic("Failed to create Vulkan instance.\n");
|
ircolib::panic("Failed to create Vulkan instance.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto tmp_surface = platform->create_surface(new_context->get_instance(), VK_NULL_HANDLE);
|
const auto tmp_surface = platform->create_surface(new_context->get_instance(), VK_NULL_HANDLE);
|
||||||
@@ -51,7 +51,7 @@ Util::IntrusivePtr<Context> InitVulkanContext(WSIPlatform *platform, const unsig
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
panic("Failed to create Vulkan device.\n");
|
ircolib::panic("Failed to create Vulkan device.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_context;
|
return new_context;
|
||||||
@@ -67,15 +67,15 @@ void ParallelRDP::LoadWSIPlatform(const std::shared_ptr<WSIPlatform> &wsi_platfo
|
|||||||
|
|
||||||
if (constexpr Context::SystemHandles handles;
|
if (constexpr Context::SystemHandles handles;
|
||||||
!wsi->init_from_existing_context(InitVulkanContext(wsi_platform.get(), 1, handles, instanceFactory))) {
|
!wsi->init_from_existing_context(InitVulkanContext(wsi_platform.get(), 1, handles, instanceFactory))) {
|
||||||
panic("Failed to initialize WSI: init_from_existing_context() failed");
|
ircolib::panic("Failed to initialize WSI: init_from_existing_context() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wsi->init_device()) {
|
if (!wsi->init_device()) {
|
||||||
panic("Failed to initialize WSI: init_device() failed");
|
ircolib::panic("Failed to initialize WSI: init_device() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wsi->init_surface_swapchain()) {
|
if (!wsi->init_surface_swapchain()) {
|
||||||
panic("Failed to initialize WSI: init_surface_swapchain() failed");
|
ircolib::panic("Failed to initialize WSI: init_surface_swapchain() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
windowInfo = newWindowInfo;
|
windowInfo = newWindowInfo;
|
||||||
@@ -124,7 +124,8 @@ void ParallelRDP::Init(const std::shared_ptr<WSIPlatform> &wsiPlatform,
|
|||||||
offset, 8 * 1024 * 1024, 4 * 1024 * 1024, flags);
|
offset, 8 * 1024 * 1024, 4 * 1024 * 1024, flags);
|
||||||
|
|
||||||
if (!command_processor->device_is_supported()) {
|
if (!command_processor->device_is_supported()) {
|
||||||
panic("This device probably does not support 8/16-bit storage. Make sure you're using up-to-date drivers!");
|
ircolib::panic(
|
||||||
|
"This device probably does not support 8/16-bit storage. Make sure you're using up-to-date drivers!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ u32 Core::StepCPU() {
|
|||||||
if (cpuType == CachedInterpreter)
|
if (cpuType == CachedInterpreter)
|
||||||
return interpreter.ExecuteCached() + regs.PopStalledCycles();
|
return interpreter.ExecuteCached() + regs.PopStalledCycles();
|
||||||
|
|
||||||
panic("Invalid CPU type?");
|
ircolib::panic("Invalid CPU type?");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::StepRSP(const u32 cpuCycles) {
|
void Core::StepRSP(const u32 cpuCycles) {
|
||||||
|
|||||||
@@ -73,15 +73,15 @@ std::string GameDB::match(ROM &rom) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
info("Matched code for {}, but not region! Game supposedly exists in regions [{}] but this image has "
|
ircolib::info("Matched code for {}, but not region! Game supposedly exists in regions [{}] but this image has "
|
||||||
"region {}",
|
"region {}",
|
||||||
name, regions, rom.header.countryCode);
|
name, regions, rom.header.countryCode);
|
||||||
rom.saveType = saveType;
|
rom.saveType = saveType;
|
||||||
rom.gameNameDB = name;
|
rom.gameNameDB = name;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
info("Did not match any Game DB entries. Code: {} Region: {}", rom.code, rom.header.countryCode);
|
ircolib::info("Did not match any Game DB entries. Code: {} Region: {}", rom.code, rom.header.countryCode);
|
||||||
|
|
||||||
rom.gameNameDB = "";
|
rom.gameNameDB = "";
|
||||||
rom.saveType = SAVE_NONE;
|
rom.saveType = SAVE_NONE;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <Netplay.hpp>
|
#include <Netplay.hpp>
|
||||||
#include <PIF.hpp>
|
#include <PIF.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace Netplay {}
|
namespace Netplay {}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <ircolib/mem_access.hpp>
|
#include <ircolib/mem_access.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace Util {
|
namespace Util {
|
||||||
#define Z64 0x80371200
|
#define Z64 0x80371200
|
||||||
@@ -13,7 +13,7 @@ FORCE_INLINE void SwapN64Rom(std::vector<u8> &rom, u32 endianness) {
|
|||||||
if (endianness >> 24 != 0x80) {
|
if (endianness >> 24 != 0x80) {
|
||||||
if ((endianness & 0xFF) != 0x80) {
|
if ((endianness & 0xFF) != 0x80) {
|
||||||
if ((endianness >> 16 & 0xff) != 0x80) {
|
if ((endianness >> 16 & 0xff) != 0x80) {
|
||||||
panic("Unrecognized rom endianness");
|
ircolib::panic("Unrecognized rom endianness");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
altByteShift = 12;
|
altByteShift = 12;
|
||||||
@@ -29,20 +29,20 @@ FORCE_INLINE void SwapN64Rom(std::vector<u8> &rom, u32 endianness) {
|
|||||||
|
|
||||||
switch (endianness) {
|
switch (endianness) {
|
||||||
case V64:
|
case V64:
|
||||||
ircolib::SwapBuffer<u16>(rom);
|
ircolib::swap_buffer<u16>(rom);
|
||||||
if constexpr (!toBE)
|
if constexpr (!toBE)
|
||||||
ircolib::SwapBuffer<u32>(rom);
|
ircolib::swap_buffer<u32>(rom);
|
||||||
break;
|
break;
|
||||||
case N64:
|
case N64:
|
||||||
if constexpr (toBE)
|
if constexpr (toBE)
|
||||||
ircolib::SwapBuffer<u32>(rom);
|
ircolib::swap_buffer<u32>(rom);
|
||||||
break;
|
break;
|
||||||
case Z64:
|
case Z64:
|
||||||
if constexpr (!toBE)
|
if constexpr (!toBE)
|
||||||
ircolib::SwapBuffer<u32>(rom);
|
ircolib::swap_buffer<u32>(rom);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!");
|
ircolib::panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace Util
|
} // namespace Util
|
||||||
|
|||||||
@@ -63,10 +63,10 @@ void Scheduler::HandleEvents() {
|
|||||||
case NONE:
|
case NONE:
|
||||||
break;
|
break;
|
||||||
case IMPOSSIBLE:
|
case IMPOSSIBLE:
|
||||||
panic("Impossible scheduler event happened");
|
ircolib::panic("Impossible scheduler event happened");
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
panic("Unknown scheduler event type {}", static_cast<int>(type));
|
ircolib::panic("Unknown scheduler event type {}", static_cast<int>(type));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
events.pop();
|
events.pop();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <types.hpp>
|
||||||
|
|
||||||
enum EventType { NONE, PAUSE, STOP, RESET, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE };
|
enum EventType { NONE, PAUSE, STOP, RESET, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE };
|
||||||
|
|
||||||
|
|||||||
@@ -3,75 +3,69 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const {
|
Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const {
|
||||||
cs_insn *insn;
|
cs_insn *insn;
|
||||||
const auto bytes = ircolib::IntegralToBuffer(std::byteswap(instruction));
|
const auto bytes = ircolib::integral_to_buffer(std::byteswap(instruction));
|
||||||
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
|
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
|
||||||
|
|
||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
DisassemblyResult result{true, std::format("0x{:016X}:\t{}\t{}", insn[0].address, insn[0].mnemonic, insn[0].op_str)};
|
DisassemblyResult result{true,
|
||||||
|
std::format("0x{:016X}:\t{}\t{}", insn[0].address, insn[0].mnemonic, insn[0].op_str)};
|
||||||
|
|
||||||
cs_free(insn, count);
|
cs_free(insn, count);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Disassembler::DisassemblyResult Disassembler::Disassemble(const u32 address) const {
|
[[nodiscard]] Disassembler::DisassemblyResult Disassembler::Disassemble(const u32 address) const {
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if(!n64::Core::GetRegs().cop0.MapVAddr(n64::Cop0::TLBAccessType::LOAD, address, paddr))
|
if (!n64::Core::GetRegs().cop0.MapVAddr(n64::Cop0::TLBAccessType::LOAD, address, paddr))
|
||||||
return DisassemblyResult{false, ""};
|
return DisassemblyResult{false, ""};
|
||||||
|
|
||||||
u32 instruction = n64::Core::GetMem().Read<u32>(paddr);
|
u32 instruction = n64::Core::GetMem().Read<u32>(paddr);
|
||||||
|
|
||||||
return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction);
|
return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const {
|
Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const {
|
||||||
n64::Core& core = n64::Core::GetInstance();
|
n64::Core &core = n64::Core::GetInstance();
|
||||||
cs_insn *insn;
|
cs_insn *insn;
|
||||||
const auto bytes = ircolib::IntegralToBuffer(std::byteswap(instruction));
|
const auto bytes = ircolib::integral_to_buffer(std::byteswap(instruction));
|
||||||
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
|
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
|
||||||
|
|
||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
DisassemblyResult result{true};
|
DisassemblyResult result{true};
|
||||||
result.address = insn[0].address;
|
result.address = insn[0].address;
|
||||||
result.mnemonic = insn[0].mnemonic;
|
result.mnemonic = insn[0].mnemonic;
|
||||||
|
|
||||||
result.full += std::format("0x{:016X}", result.address) + ":\t";
|
result.full += std::format("0x{:016X}", result.address) + ":\t";
|
||||||
result.full += result.mnemonic + "\t";
|
result.full += result.mnemonic + "\t";
|
||||||
|
|
||||||
const cs_detail *details = insn[0].detail;
|
const cs_detail *details = insn[0].detail;
|
||||||
auto formatOperand = [&](const cs_mips_op &operand) {
|
auto formatOperand = [&](const cs_mips_op &operand) {
|
||||||
switch (operand.type) {
|
switch (operand.type) {
|
||||||
case MIPS_OP_IMM:
|
case MIPS_OP_IMM:
|
||||||
return DisassemblyResult::Operand{
|
return DisassemblyResult::Operand{0xffcbf1ae,
|
||||||
0xffcbf1ae,
|
std::format("#{:X}", operand.is_unsigned ? operand.uimm : operand.imm)};
|
||||||
std::format("#{:X}", operand.is_unsigned ? operand.uimm : operand.imm)
|
case MIPS_OP_MEM:
|
||||||
};
|
return DisassemblyResult::Operand{
|
||||||
case MIPS_OP_MEM:
|
0xffaef1c3, std::format("{}(0x{:X})", cs_reg_name(handle, operand.mem.base), operand.mem.disp)};
|
||||||
return DisassemblyResult::Operand{
|
case MIPS_OP_REG:
|
||||||
0xffaef1c3,
|
return DisassemblyResult::Operand{0xffaef1eb, std::format("{}", cs_reg_name(handle, operand.reg))};
|
||||||
std::format("{}(0x{:X})", cs_reg_name(handle, operand.mem.base), operand.mem.disp)
|
default:
|
||||||
};
|
return DisassemblyResult::Operand{0xff808080, ""};
|
||||||
case MIPS_OP_REG:
|
}
|
||||||
return DisassemblyResult::Operand{
|
};
|
||||||
0xffaef1eb,
|
|
||||||
std::format("{}", cs_reg_name(handle, operand.reg))
|
for (u8 i = 0; i < details->mips.op_count && i < 3; i++) {
|
||||||
};
|
result.ops[i] = formatOperand(details->mips.operands[i]);
|
||||||
default:
|
result.full += result.ops[i].str + "\t";
|
||||||
return DisassemblyResult::Operand { 0xff808080, "" };
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
for (u8 i = 0; i < details->mips.op_count && i < 3; i++) {
|
cs_free(insn, count);
|
||||||
result.ops[i] = formatOperand(details->mips.operands[i]);
|
|
||||||
result.full += result.ops[i].str + "\t";
|
|
||||||
}
|
|
||||||
|
|
||||||
cs_free(insn, count);
|
return result;
|
||||||
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <capstone/capstone.h>
|
#include <capstone/capstone.h>
|
||||||
#include <utils/log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <ircolib/mem_access.hpp>
|
#include <ircolib/mem_access.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <types.hpp>
|
||||||
|
|
||||||
struct Disassembler {
|
struct Disassembler {
|
||||||
struct DisassemblyResult {
|
struct DisassemblyResult {
|
||||||
@@ -32,11 +33,11 @@ struct Disassembler {
|
|||||||
explicit Disassembler(const bool rsp) : rsp(rsp) {
|
explicit Disassembler(const bool rsp) : rsp(rsp) {
|
||||||
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN),
|
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN),
|
||||||
&handle) != CS_ERR_OK) {
|
&handle) != CS_ERR_OK) {
|
||||||
panic("Could not initialize {} disassembler!", rsp ? "RSP" : "CPU");
|
ircolib::panic("Could not initialize {} disassembler!", rsp ? "RSP" : "CPU");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON) != CS_ERR_OK) {
|
if (cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON) != CS_ERR_OK) {
|
||||||
warn("Could not enable disassembler's details!");
|
ircolib::warn("Could not enable disassembler's details!");
|
||||||
details = false;
|
details = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ bool Interpreter::DetectIdleLoop(const std::array<Instruction, MAX_INSTR_PER_BLO
|
|||||||
const u64 address = regs.Read<s64>(load.rs()) + offset;
|
const u64 address = regs.Read<s64>(load.rs()) + offset;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr))
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr))
|
||||||
panic("Failed to translate load address in DetectIdleLoop");
|
ircolib::panic("Failed to translate load address in DetectIdleLoop");
|
||||||
|
|
||||||
return isLoad && delay.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -8 &&
|
return isLoad && delay.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -8 &&
|
||||||
load.rt() == delay.rs() && delay.rt() == branch.rs() && IsAddressMMIOorRDRAM(paddr);
|
load.rt() == delay.rs() && delay.rt() == branch.rs() && IsAddressMMIOorRDRAM(paddr);
|
||||||
@@ -148,7 +148,7 @@ bool Interpreter::DetectIdleLoop(const std::array<Instruction, MAX_INSTR_PER_BLO
|
|||||||
if (isLoad) {
|
if (isLoad) {
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr))
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr))
|
||||||
panic("Failed to translate load address in DetectIdleLoop");
|
ircolib::panic("Failed to translate load address in DetectIdleLoop");
|
||||||
|
|
||||||
return isLoad && andi.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -12 &&
|
return isLoad && andi.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -12 &&
|
||||||
load.rt() == andi.rs() && andi.rt() == branch.rs() && IsAddressMMIOorRDRAM(paddr);
|
load.rt() == andi.rs() && andi.rt() == branch.rs() && IsAddressMMIOorRDRAM(paddr);
|
||||||
@@ -234,7 +234,7 @@ u32 Interpreter::ExecuteCached() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (blockCycles == 0)
|
if (blockCycles == 0)
|
||||||
panic("Cycles are 0");
|
ircolib::panic("Cycles are 0");
|
||||||
|
|
||||||
return blockCycles;
|
return blockCycles;
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-56
@@ -3,67 +3,67 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void MMIO::Reset() {
|
void MMIO::Reset() {
|
||||||
rsp.Reset();
|
rsp.Reset();
|
||||||
rdp.Reset();
|
rdp.Reset();
|
||||||
mi.Reset();
|
mi.Reset();
|
||||||
vi.Reset();
|
vi.Reset();
|
||||||
ai.Reset();
|
ai.Reset();
|
||||||
pi.Reset();
|
pi.Reset();
|
||||||
ri.Reset();
|
ri.Reset();
|
||||||
si.Reset();
|
si.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 MMIO::Read(u32 addr) {
|
u32 MMIO::Read(u32 addr) {
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case RSP_REGION:
|
case RSP_REGION:
|
||||||
return rsp.Read(addr);
|
return rsp.Read(addr);
|
||||||
case RDP_REGION:
|
case RDP_REGION:
|
||||||
return rdp.Read(addr);
|
return rdp.Read(addr);
|
||||||
case MI_REGION:
|
case MI_REGION:
|
||||||
return mi.Read(addr);
|
return mi.Read(addr);
|
||||||
case VI_REGION:
|
case VI_REGION:
|
||||||
return vi.Read(addr);
|
return vi.Read(addr);
|
||||||
case AI_REGION:
|
case AI_REGION:
|
||||||
return ai.Read(addr);
|
return ai.Read(addr);
|
||||||
case PI_REGION:
|
case PI_REGION:
|
||||||
return pi.Read(addr);
|
return pi.Read(addr);
|
||||||
case RI_REGION:
|
case RI_REGION:
|
||||||
return ri.Read(addr);
|
return ri.Read(addr);
|
||||||
case SI_REGION:
|
case SI_REGION:
|
||||||
return si.Read(addr);
|
return si.Read(addr);
|
||||||
default:
|
default:
|
||||||
panic("Unhandled mmio read at addr {:08X}", addr);
|
ircolib::panic("Unhandled mmio read at addr {:08X}", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MMIO::Write(const u32 addr, const u32 val) {
|
void MMIO::Write(const u32 addr, const u32 val) {
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case RSP_REGION:
|
case RSP_REGION:
|
||||||
rsp.Write(addr, val);
|
rsp.Write(addr, val);
|
||||||
break;
|
break;
|
||||||
case RDP_REGION:
|
case RDP_REGION:
|
||||||
rdp.Write(addr, val);
|
rdp.Write(addr, val);
|
||||||
break;
|
break;
|
||||||
case MI_REGION:
|
case MI_REGION:
|
||||||
mi.Write(addr, val);
|
mi.Write(addr, val);
|
||||||
break;
|
break;
|
||||||
case VI_REGION:
|
case VI_REGION:
|
||||||
vi.Write(addr, val);
|
vi.Write(addr, val);
|
||||||
break;
|
break;
|
||||||
case AI_REGION:
|
case AI_REGION:
|
||||||
ai.Write(addr, val);
|
ai.Write(addr, val);
|
||||||
break;
|
break;
|
||||||
case PI_REGION:
|
case PI_REGION:
|
||||||
pi.Write(addr, val);
|
pi.Write(addr, val);
|
||||||
break;
|
break;
|
||||||
case RI_REGION:
|
case RI_REGION:
|
||||||
ri.Write(addr, val);
|
ri.Write(addr, val);
|
||||||
break;
|
break;
|
||||||
case SI_REGION:
|
case SI_REGION:
|
||||||
si.Write(addr, val);
|
si.Write(addr, val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled mmio write at addr {:08X} with val {:08X}", addr, val);
|
ircolib::panic("Unhandled mmio write at addr {:08X} with val {:08X}", addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
+148
-144
@@ -20,7 +20,7 @@ void Mem::Reset() {
|
|||||||
std::error_code err;
|
std::error_code err;
|
||||||
saveData.sync(err);
|
saveData.sync(err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error("[Mem]: Could not sync save data!");
|
ircolib::error("[Mem]: Could not sync save data!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
saveData.unmap();
|
saveData.unmap();
|
||||||
@@ -39,26 +39,26 @@ void Mem::LoadSRAM(SaveType save_type, fs::path path) {
|
|||||||
if (saveData.is_mapped()) {
|
if (saveData.is_mapped()) {
|
||||||
saveData.sync(err);
|
saveData.sync(err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error(R"([Mem]: Could not sync save data stored @ "{}")", sramPath);
|
ircolib::error(R"([Mem]: Could not sync save data stored @ "{}")", sramPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
saveData.unmap();
|
saveData.unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sramVec = ircolib::ReadFileBinary(sramPath);
|
auto sramVec = ircolib::read_file_binary(sramPath);
|
||||||
if (sramVec.empty()) {
|
if (sramVec.empty()) {
|
||||||
ircolib::WriteFileBinary(std::array<u8, SRAM_SIZE>{}, sramPath);
|
ircolib::write_file_binary(std::array<u8, SRAM_SIZE>{}, sramPath);
|
||||||
sramVec = ircolib::ReadFileBinary(sramPath);
|
sramVec = ircolib::read_file_binary(sramPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sramVec.size() != SRAM_SIZE) {
|
if (sramVec.size() != SRAM_SIZE) {
|
||||||
error("[Mem]: Save data is corrupt or has unexpected size! (it's {} KiB)", sramVec.size() / 1024);
|
ircolib::error("[Mem]: Save data is corrupt or has unexpected size! (it's {} KiB)", sramVec.size() / 1024);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveData = mio::make_mmap_sink(sramPath, err);
|
saveData = mio::make_mmap_sink(sramPath, err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error(R"([Mem]: Could not create file sink for save data @ "{}")", sramPath);
|
ircolib::error(R"([Mem]: Could not create file sink for save data @ "{}")", sramPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ FORCE_INLINE void SetROMCIC(u32 checksum, ROM &rom) {
|
|||||||
rom.cicType = CIC_NUS_6106_7106;
|
rom.cicType = CIC_NUS_6106_7106;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
warn("Could not determine CIC TYPE! Checksum: 0x{:08X} is unknown!", checksum);
|
ircolib::warn("Could not determine CIC TYPE! Checksum: 0x{:08X} is unknown!", checksum);
|
||||||
rom.cicType = UNKNOWN_CIC_TYPE;
|
rom.cicType = UNKNOWN_CIC_TYPE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ ROM Mem::LoadROM(const bool isArchive, const std::string &filename) {
|
|||||||
buf = Util::OpenROM(filename, sizeAdjusted);
|
buf = Util::OpenROM(filename, sizeAdjusted);
|
||||||
}
|
}
|
||||||
|
|
||||||
endianness = std::byteswap(ircolib::ReadAccess<u32>(buf, 0));
|
endianness = std::byteswap(ircolib::read_access<u32>(buf, 0));
|
||||||
Util::SwapN64Rom<true>(buf, endianness);
|
Util::SwapN64Rom<true>(buf, endianness);
|
||||||
|
|
||||||
std::ranges::copy(buf, res.cart.begin());
|
std::ranges::copy(buf, res.cart.begin());
|
||||||
@@ -130,7 +130,7 @@ ROM Mem::LoadROM(const bool isArchive, const std::string &filename) {
|
|||||||
|
|
||||||
const u32 checksum = SDL_crc32(0, &res.cart[0x40], 0x9C0);
|
const u32 checksum = SDL_crc32(0, &res.cart[0x40], 0x9C0);
|
||||||
SetROMCIC(checksum, res);
|
SetROMCIC(checksum, res);
|
||||||
endianness = std::byteswap(ircolib::ReadAccess<u32>(res.cart, 0));
|
endianness = std::byteswap(ircolib::read_access<u32>(res.cart, 0));
|
||||||
Util::SwapN64Rom(res.cart, endianness);
|
Util::SwapN64Rom(res.cart, endianness);
|
||||||
res.pal = IsROMPAL(res);
|
res.pal = IsROMPAL(res);
|
||||||
return res;
|
return res;
|
||||||
@@ -141,38 +141,38 @@ u8 Mem::Read(const u32 paddr) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
const SI &si = mmio.si;
|
const SI &si = mmio.si;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
if (ircolib::is_inside_range(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
return mmio.rdp.ReadRDRAM<u8>(paddr);
|
return mmio.rdp.ReadRDRAM<u8>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
if (ircolib::is_inside_range(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
||||||
return mmio.pi.BusRead<u8, false>(paddr);
|
return mmio.pi.BusRead<u8, false>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, AI_REGION_START, AI_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, AI_REGION_START, AI_REGION_END)) {
|
||||||
const u32 w = mmio.ai.Read(paddr & ~3);
|
const u32 w = mmio.ai.Read(paddr & ~3);
|
||||||
const int offs = 3 - (paddr & 3);
|
const int offs = 3 - (paddr & 3);
|
||||||
return w >> offs * 8 & 0xff;
|
return w >> offs * 8 & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) {
|
ircolib::is_inside_range(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) {
|
||||||
panic("8-bit read access from MMIO addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
ircolib::panic("8-bit read access from MMIO addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
if (ircolib::is_inside_range(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
||||||
return si.pif.bootrom[BYTE_ADDRESS(paddr) - PIF_ROM_REGION_START];
|
return si.pif.bootrom[BYTE_ADDRESS(paddr) - PIF_ROM_REGION_START];
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END))
|
if (ircolib::is_inside_range(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END))
|
||||||
return si.pif.ram[paddr - PIF_RAM_REGION_START];
|
return si.pif.ram[paddr - PIF_RAM_REGION_START];
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
if (ircolib::is_inside_range(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
ircolib::is_inside_range(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
panic("8-bit read access in unhandled addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
ircolib::panic("8-bit read access in unhandled addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,29 +181,29 @@ u16 Mem::Read(const u32 paddr) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
const SI &si = mmio.si;
|
const SI &si = mmio.si;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
if (ircolib::is_inside_range(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
return mmio.rdp.ReadRDRAM<u16>(paddr);
|
return mmio.rdp.ReadRDRAM<u16>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
return ircolib::ReadAccess<u16>(src, HALF_ADDRESS(paddr & 0xfff));
|
return ircolib::read_access<u16>(src, HALF_ADDRESS(paddr & 0xfff));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
if (ircolib::is_inside_range(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
||||||
return mmio.pi.BusRead<u16, false>(paddr);
|
return mmio.pi.BusRead<u16, false>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
ircolib::is_inside_range(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
return mmio.Read(paddr);
|
return mmio.Read(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
if (ircolib::is_inside_range(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
||||||
return ircolib::ReadAccess<u16>(si.pif.bootrom, HALF_ADDRESS(paddr) - PIF_ROM_REGION_START);
|
return ircolib::read_access<u16>(si.pif.bootrom, HALF_ADDRESS(paddr) - PIF_ROM_REGION_START);
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END))
|
if (ircolib::is_inside_range(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END))
|
||||||
return std::byteswap(ircolib::ReadAccess<u16>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
return std::byteswap(ircolib::read_access<u16>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
if (ircolib::is_inside_range(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
ircolib::is_inside_range(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
panic("16-bit read access in unhandled addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
ircolib::panic("16-bit read access in unhandled addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,30 +212,30 @@ u32 Mem::Read(const u32 paddr) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
const SI &si = mmio.si;
|
const SI &si = mmio.si;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
if (ircolib::is_inside_range(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
return mmio.rdp.ReadRDRAM<u32>(paddr);
|
return mmio.rdp.ReadRDRAM<u32>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
return ircolib::ReadAccess<u32>(src, paddr & 0xfff);
|
return ircolib::read_access<u32>(src, paddr & 0xfff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
if (ircolib::is_inside_range(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
||||||
return mmio.pi.BusRead<u32, false>(paddr);
|
return mmio.pi.BusRead<u32, false>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
ircolib::is_inside_range(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
return mmio.Read(paddr);
|
return mmio.Read(paddr);
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
if (ircolib::is_inside_range(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
||||||
return ircolib::ReadAccess<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
return ircolib::read_access<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END))
|
if (ircolib::is_inside_range(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END))
|
||||||
return std::byteswap(ircolib::ReadAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
return std::byteswap(ircolib::read_access<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
if (ircolib::is_inside_range(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
ircolib::is_inside_range(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
panic("32-bit read access in unhandled addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
ircolib::panic("32-bit read access in unhandled addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,30 +244,30 @@ u64 Mem::Read(const u32 paddr) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
const SI &si = mmio.si;
|
const SI &si = mmio.si;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
if (ircolib::is_inside_range(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
return mmio.rdp.ReadRDRAM<u64>(paddr);
|
return mmio.rdp.ReadRDRAM<u64>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
return ircolib::ReadAccess<u64>(src, paddr & 0xfff);
|
return ircolib::read_access<u64>(src, paddr & 0xfff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
if (ircolib::is_inside_range(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
||||||
return mmio.pi.BusRead<u64, false>(paddr);
|
return mmio.pi.BusRead<u64, false>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
ircolib::is_inside_range(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
return mmio.Read(paddr);
|
return mmio.Read(paddr);
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
if (ircolib::is_inside_range(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
||||||
return ircolib::ReadAccess<u64>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
return ircolib::read_access<u64>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END))
|
if (ircolib::is_inside_range(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END))
|
||||||
return std::byteswap(ircolib::ReadAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
return std::byteswap(ircolib::read_access<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
if (ircolib::is_inside_range(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
ircolib::is_inside_range(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
panic("64-bit read access in unhandled addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
ircolib::panic("64-bit read access in unhandled addr 0x{:08X} @ pc 0x{:016X}", paddr, (u64)regs.pc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,45 +276,46 @@ void Mem::Write<u8>(u32 paddr, u32 val) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
SI &si = mmio.si;
|
SI &si = mmio.si;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
||||||
mmio.rdp.WriteRDRAM<u8>(paddr, val);
|
mmio.rdp.WriteRDRAM<u8>(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
val = val << (8 * (3 - (paddr & 3)));
|
val = val << (8 * (3 - (paddr & 3)));
|
||||||
bool is_imem = paddr & 0x1000;
|
bool is_imem = paddr & 0x1000;
|
||||||
auto &dest = is_imem ? mmio.rsp.imem : mmio.rsp.dmem;
|
auto &dest = is_imem ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
paddr = (paddr & 0xFFF) & ~3;
|
paddr = (paddr & 0xFFF) & ~3;
|
||||||
ircolib::WriteAccess<u32>(dest, paddr, val);
|
ircolib::write_access<u32>(dest, paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) {
|
if (ircolib::is_inside_range(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) {
|
||||||
trace("BusWrite<u8> @ {:08X} = {:02X}", paddr, val);
|
ircolib::trace("BusWrite<u8> @ {:08X} = {:02X}", paddr, val);
|
||||||
mmio.pi.BusWrite<u8, false>(paddr, val);
|
mmio.pi.BusWrite<u8, false>(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
ircolib::is_inside_range(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
panic("MMIO Write<u8>!");
|
ircolib::panic("MMIO Write<u8>!");
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
|
||||||
val = val << (8 * (3 - (paddr & 3)));
|
val = val << (8 * (3 - (paddr & 3)));
|
||||||
paddr = (paddr - PIF_RAM_REGION_START) & ~3;
|
paddr = (paddr - PIF_RAM_REGION_START) & ~3;
|
||||||
ircolib::WriteAccess<u32>(si.pif.ram, paddr, std::byteswap(val));
|
ircolib::write_access<u32>(si.pif.ram, paddr, std::byteswap(val));
|
||||||
si.pif.ProcessCommands();
|
si.pif.ProcessCommands();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
if (ircolib::is_inside_range(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
ircolib::is_inside_range(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
ircolib::is_inside_range(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
panic("Unimplemented 8-bit write at address {:08X} with value {:02X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
ircolib::panic("Unimplemented 8-bit write at address {:08X} with value {:02X} (PC = {:016X})", paddr, val,
|
||||||
|
(u64)regs.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@@ -322,45 +323,46 @@ void Mem::Write<u16>(u32 paddr, u32 val) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
SI &si = mmio.si;
|
SI &si = mmio.si;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
||||||
mmio.rdp.WriteRDRAM<u16>(paddr, val);
|
mmio.rdp.WriteRDRAM<u16>(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
val = val << (16 * !(paddr & 2));
|
val = val << (16 * !(paddr & 2));
|
||||||
bool is_imem = paddr & 0x1000;
|
bool is_imem = paddr & 0x1000;
|
||||||
auto &dest = is_imem ? mmio.rsp.imem : mmio.rsp.dmem;
|
auto &dest = is_imem ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
paddr = (paddr & 0xFFF) & ~3;
|
paddr = (paddr & 0xFFF) & ~3;
|
||||||
ircolib::WriteAccess<u32>(dest, paddr, val);
|
ircolib::write_access<u32>(dest, paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) {
|
if (ircolib::is_inside_range(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) {
|
||||||
trace("BusWrite<u8> @ {:08X} = {:04X}", paddr, val);
|
ircolib::trace("BusWrite<u8> @ {:08X} = {:04X}", paddr, val);
|
||||||
mmio.pi.BusWrite<u16, false>(paddr, val);
|
mmio.pi.BusWrite<u16, false>(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
ircolib::is_inside_range(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
panic("MMIO Write<u16>!");
|
ircolib::panic("MMIO Write<u16>!");
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
|
||||||
val = val << (16 * !(paddr & 2));
|
val = val << (16 * !(paddr & 2));
|
||||||
paddr &= ~3;
|
paddr &= ~3;
|
||||||
ircolib::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
ircolib::write_access<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
||||||
si.pif.ProcessCommands();
|
si.pif.ProcessCommands();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
if (ircolib::is_inside_range(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
ircolib::is_inside_range(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
ircolib::is_inside_range(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
panic("Unimplemented 16-bit write at address {:08X} with value {:04X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
ircolib::panic("Unimplemented 16-bit write at address {:08X} with value {:04X} (PC = {:016X})", paddr, val,
|
||||||
|
(u64)regs.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@@ -368,85 +370,87 @@ void Mem::Write<u32>(const u32 paddr, const u32 val) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
SI &si = mmio.si;
|
SI &si = mmio.si;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
||||||
mmio.rdp.WriteRDRAM<u32>(paddr, val);
|
mmio.rdp.WriteRDRAM<u32>(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
bool is_imem = paddr & 0x1000;
|
bool is_imem = paddr & 0x1000;
|
||||||
auto &dest = is_imem ? mmio.rsp.imem : mmio.rsp.dmem;
|
auto &dest = is_imem ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
ircolib::WriteAccess<u32>(dest, paddr & 0xfff, val);
|
ircolib::write_access<u32>(dest, paddr & 0xfff, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) {
|
if (ircolib::is_inside_range(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) {
|
||||||
trace("BusWrite<u8> @ {:08X} = {:08X}", paddr, val);
|
ircolib::trace("BusWrite<u8> @ {:08X} = {:08X}", paddr, val);
|
||||||
mmio.pi.BusWrite<u32, false>(paddr, val);
|
mmio.pi.BusWrite<u32, false>(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) {
|
ircolib::is_inside_range(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) {
|
||||||
mmio.Write(paddr, val);
|
mmio.Write(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
|
||||||
ircolib::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
ircolib::write_access<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
||||||
si.pif.ProcessCommands();
|
si.pif.ProcessCommands();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
if (ircolib::is_inside_range(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
ircolib::is_inside_range(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
ircolib::is_inside_range(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
panic("Unimplemented 32-bit write at address {:08X} with value {:08X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
ircolib::panic("Unimplemented 32-bit write at address {:08X} with value {:08X} (PC = {:016X})", paddr, val,
|
||||||
|
(u64)regs.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mem::Write(const u32 paddr, u64 val) {
|
void Mem::Write(const u32 paddr, u64 val) {
|
||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
SI &si = mmio.si;
|
SI &si = mmio.si;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
||||||
mmio.rdp.WriteRDRAM<u64>(paddr, val);
|
mmio.rdp.WriteRDRAM<u64>(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
bool is_imem = paddr & 0x1000;
|
bool is_imem = paddr & 0x1000;
|
||||||
auto &dest = is_imem ? mmio.rsp.imem : mmio.rsp.dmem;
|
auto &dest = is_imem ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
val >>= 32;
|
val >>= 32;
|
||||||
ircolib::WriteAccess<u32>(dest, paddr & 0xfff, val);
|
ircolib::write_access<u32>(dest, paddr & 0xfff, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) {
|
if (ircolib::is_inside_range(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) {
|
||||||
trace("BusWrite<u64> @ {:08X} = {:016X}", paddr, val);
|
ircolib::trace("BusWrite<u64> @ {:08X} = {:016X}", paddr, val);
|
||||||
mmio.pi.BusWrite<false>(paddr, val);
|
mmio.pi.BusWrite<false>(paddr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
ircolib::is_inside_range(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
panic("MMIO Write<u64>!");
|
ircolib::panic("MMIO Write<u64>!");
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
|
if (ircolib::is_inside_range(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
|
||||||
ircolib::WriteAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
ircolib::write_access<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
||||||
si.pif.ProcessCommands();
|
si.pif.ProcessCommands();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
if (ircolib::is_inside_range(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::is_inside_range(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
ircolib::is_inside_range(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
ircolib::is_inside_range(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
panic("Unimplemented 64-bit write at address {:08X} with value {:016X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
ircolib::panic("Unimplemented 64-bit write at address {:08X} with value {:016X} (PC = {:016X})", paddr, val,
|
||||||
|
(u64)regs.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@@ -456,14 +460,14 @@ u32 Mem::BackupRead<u32>(const u32 addr) {
|
|||||||
return 0;
|
return 0;
|
||||||
case SAVE_EEPROM_4k:
|
case SAVE_EEPROM_4k:
|
||||||
case SAVE_EEPROM_16k:
|
case SAVE_EEPROM_16k:
|
||||||
warn("Accessing cartridge backup type SAVE_EEPROM, returning 0 for word read");
|
ircolib::warn("Accessing cartridge backup type SAVE_EEPROM, returning 0 for word read");
|
||||||
return 0;
|
return 0;
|
||||||
case SAVE_FLASH_1m:
|
case SAVE_FLASH_1m:
|
||||||
return flash.Read<u32>(addr);
|
return flash.Read<u32>(addr);
|
||||||
case SAVE_SRAM_256k:
|
case SAVE_SRAM_256k:
|
||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFF;
|
||||||
default:
|
default:
|
||||||
panic("Backup read word with unknown save type");
|
ircolib::panic("Backup read word with unknown save type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +478,7 @@ u8 Mem::BackupRead<u8>(const u32 addr) {
|
|||||||
return 0;
|
return 0;
|
||||||
case SAVE_EEPROM_4k:
|
case SAVE_EEPROM_4k:
|
||||||
case SAVE_EEPROM_16k:
|
case SAVE_EEPROM_16k:
|
||||||
warn("Accessing cartridge backup type SAVE_EEPROM, returning 0 for word read");
|
ircolib::warn("Accessing cartridge backup type SAVE_EEPROM, returning 0 for word read");
|
||||||
return 0;
|
return 0;
|
||||||
case SAVE_FLASH_1m:
|
case SAVE_FLASH_1m:
|
||||||
return flash.Read<u8>(addr);
|
return flash.Read<u8>(addr);
|
||||||
@@ -483,10 +487,10 @@ u8 Mem::BackupRead<u8>(const u32 addr) {
|
|||||||
assert(addr < saveData.size());
|
assert(addr < saveData.size());
|
||||||
return saveData[addr];
|
return saveData[addr];
|
||||||
} else {
|
} else {
|
||||||
panic("Invalid backup Read<u8> if save data is not initialized");
|
ircolib::panic("Invalid backup Read<u8> if save data is not initialized");
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Backup read word with unknown save type");
|
ircolib::panic("Backup read word with unknown save type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,18 +498,18 @@ template <>
|
|||||||
void Mem::BackupWrite<u32>(const u32 addr, const u32 val) {
|
void Mem::BackupWrite<u32>(const u32 addr, const u32 val) {
|
||||||
switch (rom.saveType) {
|
switch (rom.saveType) {
|
||||||
case SAVE_NONE:
|
case SAVE_NONE:
|
||||||
warn("Accessing cartridge with save type SAVE_NONE in write word");
|
ircolib::warn("Accessing cartridge with save type SAVE_NONE in write word");
|
||||||
break;
|
break;
|
||||||
case SAVE_EEPROM_4k:
|
case SAVE_EEPROM_4k:
|
||||||
case SAVE_EEPROM_16k:
|
case SAVE_EEPROM_16k:
|
||||||
panic("Accessing cartridge with save type SAVE_EEPROM in write word");
|
ircolib::panic("Accessing cartridge with save type SAVE_EEPROM in write word");
|
||||||
case SAVE_FLASH_1m:
|
case SAVE_FLASH_1m:
|
||||||
flash.Write<u32>(addr, val);
|
flash.Write<u32>(addr, val);
|
||||||
break;
|
break;
|
||||||
case SAVE_SRAM_256k:
|
case SAVE_SRAM_256k:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Backup read word with unknown save type");
|
ircolib::panic("Backup read word with unknown save type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,11 +517,11 @@ template <>
|
|||||||
void Mem::BackupWrite<u8>(const u32 addr, const u8 val) {
|
void Mem::BackupWrite<u8>(const u32 addr, const u8 val) {
|
||||||
switch (rom.saveType) {
|
switch (rom.saveType) {
|
||||||
case SAVE_NONE:
|
case SAVE_NONE:
|
||||||
warn("Accessing cartridge with save type SAVE_NONE in write word");
|
ircolib::warn("Accessing cartridge with save type SAVE_NONE in write word");
|
||||||
break;
|
break;
|
||||||
case SAVE_EEPROM_4k:
|
case SAVE_EEPROM_4k:
|
||||||
case SAVE_EEPROM_16k:
|
case SAVE_EEPROM_16k:
|
||||||
panic("Accessing cartridge with save type SAVE_EEPROM in write word");
|
ircolib::panic("Accessing cartridge with save type SAVE_EEPROM in write word");
|
||||||
case SAVE_FLASH_1m:
|
case SAVE_FLASH_1m:
|
||||||
flash.Write<u8>(addr, val);
|
flash.Write<u8>(addr, val);
|
||||||
break;
|
break;
|
||||||
@@ -526,11 +530,11 @@ void Mem::BackupWrite<u8>(const u32 addr, const u8 val) {
|
|||||||
assert(addr < saveData.size());
|
assert(addr < saveData.size());
|
||||||
saveData[addr] = val;
|
saveData[addr] = val;
|
||||||
} else {
|
} else {
|
||||||
panic("Invalid backup Write<u8> if save data is not initialized");
|
ircolib::panic("Invalid backup Write<u8> if save data is not initialized");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Backup read word with unknown save type");
|
ircolib::panic("Backup read word with unknown save type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <backend/MemoryRegions.hpp>
|
#include <backend/MemoryRegions.hpp>
|
||||||
#include <backend/core/MMIO.hpp>
|
#include <backend/core/MMIO.hpp>
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -100,22 +100,22 @@ struct Mem {
|
|||||||
std::vector<u8> temp{};
|
std::vector<u8> temp{};
|
||||||
temp.resize(size);
|
temp.resize(size);
|
||||||
std::copy(mmio.rdp.rdram.begin() + start, mmio.rdp.rdram.begin() + size - 1, temp.begin());
|
std::copy(mmio.rdp.rdram.begin() + start, mmio.rdp.rdram.begin() + size - 1, temp.begin());
|
||||||
ircolib::SwapBuffer<u32>(temp);
|
ircolib::swap_buffer<u32>(temp);
|
||||||
ircolib::WriteFileBinary(temp, "rdram.bin");
|
ircolib::write_file_binary(temp, "rdram.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void DumpIMEM() const {
|
FORCE_INLINE void DumpIMEM() const {
|
||||||
std::array<u8, IMEM_SIZE> temp{};
|
std::array<u8, IMEM_SIZE> temp{};
|
||||||
std::ranges::copy(mmio.rsp.imem, temp.begin());
|
std::ranges::copy(mmio.rsp.imem, temp.begin());
|
||||||
ircolib::SwapBuffer<u32>(temp);
|
ircolib::swap_buffer<u32>(temp);
|
||||||
ircolib::WriteFileBinary(temp, "imem.bin");
|
ircolib::write_file_binary(temp, "imem.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void DumpDMEM() const {
|
FORCE_INLINE void DumpDMEM() const {
|
||||||
std::array<u8, DMEM_SIZE> temp{};
|
std::array<u8, DMEM_SIZE> temp{};
|
||||||
std::ranges::copy(mmio.rsp.dmem, temp.begin());
|
std::ranges::copy(mmio.rsp.dmem, temp.begin());
|
||||||
ircolib::SwapBuffer<u32>(temp);
|
ircolib::swap_buffer<u32>(temp);
|
||||||
ircolib::WriteFileBinary(temp, "dmem.bin");
|
ircolib::write_file_binary(temp, "dmem.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
MMIO mmio;
|
MMIO mmio;
|
||||||
|
|||||||
+12
-12
@@ -1,4 +1,4 @@
|
|||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <parallel-rdp/ParallelRDPWrapper.hpp>
|
#include <parallel-rdp/ParallelRDPWrapper.hpp>
|
||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
|
|
||||||
@@ -25,21 +25,21 @@ void RDP::WriteRDRAM<u8>(const size_t idx, const u8 v) {
|
|||||||
template <>
|
template <>
|
||||||
void RDP::WriteRDRAM<u16>(const size_t idx, const u16 v) {
|
void RDP::WriteRDRAM<u16>(const size_t idx, const u16 v) {
|
||||||
if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] {
|
if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] {
|
||||||
ircolib::WriteAccess<u16>(rdram, real, v);
|
ircolib::write_access<u16>(rdram, real, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void RDP::WriteRDRAM<u32>(const size_t idx, const u32 v) {
|
void RDP::WriteRDRAM<u32>(const size_t idx, const u32 v) {
|
||||||
if (idx < RDRAM_SIZE) [[likely]] {
|
if (idx < RDRAM_SIZE) [[likely]] {
|
||||||
ircolib::WriteAccess<u32>(rdram, idx, v);
|
ircolib::write_access<u32>(rdram, idx, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void RDP::WriteRDRAM<u64>(const size_t idx, const u64 v) {
|
void RDP::WriteRDRAM<u64>(const size_t idx, const u64 v) {
|
||||||
if (idx < RDRAM_SIZE) [[likely]] {
|
if (idx < RDRAM_SIZE) [[likely]] {
|
||||||
ircolib::WriteAccess<u64>(rdram, idx, v);
|
ircolib::write_access<u64>(rdram, idx, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ u8 RDP::ReadRDRAM<u8>(const size_t idx) {
|
|||||||
template <>
|
template <>
|
||||||
u16 RDP::ReadRDRAM<u16>(const size_t idx) {
|
u16 RDP::ReadRDRAM<u16>(const size_t idx) {
|
||||||
if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]]
|
if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]]
|
||||||
return ircolib::ReadAccess<u16>(rdram, real);
|
return ircolib::read_access<u16>(rdram, real);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ u16 RDP::ReadRDRAM<u16>(const size_t idx) {
|
|||||||
template <>
|
template <>
|
||||||
u32 RDP::ReadRDRAM<u32>(const size_t idx) {
|
u32 RDP::ReadRDRAM<u32>(const size_t idx) {
|
||||||
if (idx < RDRAM_SIZE) [[likely]]
|
if (idx < RDRAM_SIZE) [[likely]]
|
||||||
return ircolib::ReadAccess<u32>(rdram, idx);
|
return ircolib::read_access<u32>(rdram, idx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ u32 RDP::ReadRDRAM<u32>(const size_t idx) {
|
|||||||
template <>
|
template <>
|
||||||
u64 RDP::ReadRDRAM<u64>(const size_t idx) {
|
u64 RDP::ReadRDRAM<u64>(const size_t idx) {
|
||||||
if (idx < RDRAM_SIZE) [[likely]]
|
if (idx < RDRAM_SIZE) [[likely]]
|
||||||
return ircolib::ReadAccess<u64>(rdram, idx);
|
return ircolib::read_access<u64>(rdram, idx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ auto RDP::Read(const u32 addr) const -> u32 {
|
|||||||
case 0x0410001C:
|
case 0x0410001C:
|
||||||
return dpc.tmem;
|
return dpc.tmem;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled DP Command Registers read (addr: {:08X})", addr);
|
ircolib::panic("Unhandled DP Command Registers read (addr: {:08X})", addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -116,7 +116,7 @@ void RDP::Write(const u32 addr, const u32 val) {
|
|||||||
WriteStatus(val);
|
WriteStatus(val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val);
|
ircolib::panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,13 +216,13 @@ void RDP::RunCommand() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (len + remaining_cmds * 4 > COMMAND_BUFFER_SIZE) {
|
if (len + remaining_cmds * 4 > COMMAND_BUFFER_SIZE) {
|
||||||
panic("Too many RDP commands");
|
ircolib::panic("Too many RDP commands");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dpc.status.xbusDmemDma) {
|
if (dpc.status.xbusDmemDma) {
|
||||||
for (int i = 0; i < len; i += 4) {
|
for (int i = 0; i < len; i += 4) {
|
||||||
const u32 cmd = ircolib::ReadAccess<u32>(mem.mmio.rsp.dmem, current + i & 0xFFF);
|
const u32 cmd = ircolib::read_access<u32>(mem.mmio.rsp.dmem, current + i & 0xFFF);
|
||||||
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -231,7 +231,7 @@ void RDP::RunCommand() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < len; i += 4) {
|
for (int i = 0; i < len; i += 4) {
|
||||||
const u32 cmd = ircolib::ReadAccess<u32>(rdram, current + i);
|
const u32 cmd = ircolib::read_access<u32>(rdram, current + i);
|
||||||
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
RSP::RSP() { Reset(); }
|
RSP::RSP() { Reset(); }
|
||||||
@@ -53,8 +53,8 @@ auto RSP::Read(const u32 addr) -> u32 {
|
|||||||
{
|
{
|
||||||
auto ®s = Core::GetRegs();
|
auto ®s = Core::GetRegs();
|
||||||
|
|
||||||
panic("Unimplemented SP register read {:08X} (cpu pc: 0x{:016X}, rsp pc: 0x{:04X}, ra: 0x{:016X})", addr,
|
ircolib::panic("Unimplemented SP register read {:08X} (cpu pc: 0x{:016X}, rsp pc: 0x{:04X}, ra: 0x{:016X})",
|
||||||
(u64)regs.oldPC, pc & 0xffc, (u64)regs.gpr[31]);
|
addr, (u64)regs.oldPC, pc & 0xffc, (u64)regs.gpr[31]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,13 +111,13 @@ void RSP::DMA<true>() {
|
|||||||
|
|
||||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
||||||
trace("SP DMA from RSP to RDRAM (size: {} B, {:08X} to {:08X})", length, mem_address, dram_address);
|
ircolib::trace("SP DMA from RSP to RDRAM (size: {} B, {:08X} to {:08X})", length, mem_address, dram_address);
|
||||||
|
|
||||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||||
for (u32 j = 0; j < length; j++) {
|
for (u32 j = 0; j < length; j++) {
|
||||||
mem.mmio.rdp.WriteRDRAM<u8>(BYTE_ADDRESS(dram_address + j), src[(mem_address + j) & DMEM_DSIZE]);
|
mem.mmio.rdp.WriteRDRAM<u8>(BYTE_ADDRESS(dram_address + j), src[(mem_address + j) & DMEM_DSIZE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
const int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||||
|
|
||||||
dram_address += (length + skip);
|
dram_address += (length + skip);
|
||||||
@@ -125,7 +125,7 @@ void RSP::DMA<true>() {
|
|||||||
mem_address += length;
|
mem_address += length;
|
||||||
mem_address &= 0xFF8;
|
mem_address &= 0xFF8;
|
||||||
}
|
}
|
||||||
trace("Addresses after: RSP: 0x{:08X}, Dram: 0x{:08X}", mem_address, dram_address);
|
ircolib::trace("Addresses after: RSP: 0x{:08X}, Dram: 0x{:08X}", mem_address, dram_address);
|
||||||
|
|
||||||
lastSuccessfulSPAddr.address = mem_address;
|
lastSuccessfulSPAddr.address = mem_address;
|
||||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||||
@@ -145,7 +145,7 @@ void RSP::DMA<false>() {
|
|||||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||||
|
|
||||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
||||||
trace("SP DMA from RDRAM to RSP (size: {} B, {:08X} to {:08X})", length, dram_address, mem_address);
|
ircolib::trace("SP DMA from RDRAM to RSP (size: {} B, {:08X} to {:08X})", length, dram_address, mem_address);
|
||||||
|
|
||||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||||
for (u32 j = 0; j < length; j++) {
|
for (u32 j = 0; j < length; j++) {
|
||||||
@@ -159,7 +159,7 @@ void RSP::DMA<false>() {
|
|||||||
mem_address += length;
|
mem_address += length;
|
||||||
mem_address &= 0xFF8;
|
mem_address &= 0xFF8;
|
||||||
}
|
}
|
||||||
trace("Addresses after: RSP: 0x{:08X}, Dram: 0x{:08X}", mem_address, dram_address);
|
ircolib::trace("Addresses after: RSP: 0x{:08X}, Dram: 0x{:08X}", mem_address, dram_address);
|
||||||
|
|
||||||
lastSuccessfulSPAddr.address = mem_address;
|
lastSuccessfulSPAddr.address = mem_address;
|
||||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||||
@@ -195,7 +195,7 @@ void RSP::Write(const u32 addr, const u32 val) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented SP register write {:08X}, val: {:08X}", addr, val);
|
ircolib::panic("Unimplemented SP register write {:08X}, val: {:08X}", addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ struct RSP {
|
|||||||
|
|
||||||
FORCE_INLINE void Step() {
|
FORCE_INLINE void Step() {
|
||||||
gpr[0] = 0;
|
gpr[0] = 0;
|
||||||
const u32 instr = ircolib::ReadAccess<u32>(imem, pc & IMEM_DSIZE);
|
const u32 instr = ircolib::read_access<u32>(imem, pc & IMEM_DSIZE);
|
||||||
oldPC = pc & 0xFFC;
|
oldPC = pc & 0xFFC;
|
||||||
pc = nextPC & 0xFFC;
|
pc = nextPC & 0xFFC;
|
||||||
nextPC += 4;
|
nextPC += 4;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
@@ -42,11 +42,12 @@ void Cop0::eret() {
|
|||||||
|
|
||||||
|
|
||||||
void Cop0::tlbr() {
|
void Cop0::tlbr() {
|
||||||
if (index.i >= 32) {
|
auto i = index.i;
|
||||||
panic("TLBR with TLB index {}", index.i);
|
if (i >= 32) {
|
||||||
|
ircolib::panic("TLBR with TLB index {}", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TLBEntry entry = tlb[index.i];
|
const TLBEntry entry = tlb[i];
|
||||||
|
|
||||||
entryHi.raw = entry.entryHi.raw;
|
entryHi.raw = entry.entryHi.raw;
|
||||||
entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
|
entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
|
||||||
@@ -64,7 +65,7 @@ void Cop0::tlbw(const int index_) {
|
|||||||
page_mask.mask = top | (top >> 1);
|
page_mask.mask = top | (top >> 1);
|
||||||
|
|
||||||
if (index_ >= 32) {
|
if (index_ >= 32) {
|
||||||
panic("TLBWI with TLB index {}", index_);
|
ircolib::panic("TLBWI with TLB index {}", index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
tlb[index_].entryHi.raw = entryHi.raw;
|
tlb[index_].entryHi.raw = entryHi.raw;
|
||||||
|
|||||||
@@ -555,7 +555,7 @@ void Cop1::cfc1(const Instruction instr) {
|
|||||||
val = fcr31.read();
|
val = fcr31.read();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Undefined CFC1 with rd != 0 or 31");
|
ircolib::panic("Undefined CFC1 with rd != 0 or 31");
|
||||||
}
|
}
|
||||||
regs.Write(instr.rt(), val);
|
regs.Write(instr.rt(), val);
|
||||||
}
|
}
|
||||||
@@ -604,7 +604,7 @@ void Cop1::ctc1(const Instruction instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Undefined CTC1 with rd != 0 or 31");
|
ircolib::panic("Undefined CTC1 with rd != 0 or 31");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <Instruction.hpp>
|
#include <Instruction.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
@@ -164,8 +164,8 @@ void Interpreter::special(const Instruction instr) {
|
|||||||
dsra32(instr);
|
dsra32(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.special_hi,
|
ircolib::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.special_hi,
|
||||||
instr.instr.opcode.special_lo, instr.instr.raw, static_cast<u64>(regs.oldPC));
|
instr.instr.opcode.special_lo, instr.instr.raw, static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,8 +215,8 @@ void Interpreter::regimm(const Instruction instr) {
|
|||||||
bllink(instr, regs.Read<s64>(instr.rs()) >= 0);
|
bllink(instr, regs.Read<s64>(instr.rs()) >= 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.regimm_hi,
|
ircolib::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.regimm_hi,
|
||||||
instr.instr.opcode.regimm_lo, u32(instr), static_cast<u64>(regs.oldPC));
|
instr.instr.opcode.regimm_lo, u32(instr), static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ void Interpreter::DecodeExecute(const Instruction instr) {
|
|||||||
bl(instr, regs.cop1.fcr31.compare);
|
bl(instr, regs.cop1.fcr31.compare);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Undefined BC COP1 {:02X}", instr.cop_rt());
|
ircolib::panic("Undefined BC COP1 {:02X}", instr.cop_rt());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -450,8 +450,8 @@ void Interpreter::DecodeExecute(const Instruction instr) {
|
|||||||
sd(instr);
|
sd(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.instr.opcode.op, u32(instr),
|
ircolib::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.instr.opcode.op, u32(instr),
|
||||||
static_cast<u64>(regs.oldPC));
|
static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -876,7 +876,7 @@ void Interpreter::cache(const Instruction instr) {
|
|||||||
u32 ptag = GetPhysicalAddressPTag(paddr);
|
u32 ptag = GetPhysicalAddressPTag(paddr);
|
||||||
|
|
||||||
if (type > 1)
|
if (type > 1)
|
||||||
panic("Unknown cache type {}", type);
|
ircolib::panic("Unknown cache type {}", type);
|
||||||
|
|
||||||
if (type == 0)
|
if (type == 0)
|
||||||
return CacheTypeInstruction(op, vaddr, paddr, ptag);
|
return CacheTypeInstruction(op, vaddr, paddr, ptag);
|
||||||
@@ -905,7 +905,7 @@ void Interpreter::CacheTypeInstruction(const u8 op, const u64 vaddr, const u32 p
|
|||||||
icache.WriteBack(vaddr, paddr, ptag);
|
icache.WriteBack(vaddr, paddr, ptag);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented icache op 0b{:03b}", op);
|
ircolib::panic("Unimplemented icache op 0b{:03b}", op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -941,7 +941,7 @@ void Interpreter::CacheTypeData(const u8 op, const u64 vaddr, const u32 paddr, c
|
|||||||
dcache.WriteBack(vaddr, paddr, ptag);
|
dcache.WriteBack(vaddr, paddr, ptag);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented dcache op 0b{:03b}", op);
|
ircolib::panic("Unimplemented dcache op 0b{:03b}", op);
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -28,32 +28,32 @@ void Flash::Load(SaveType saveType, const std::string &path) {
|
|||||||
if (saveData.is_mapped()) {
|
if (saveData.is_mapped()) {
|
||||||
saveData.sync(error);
|
saveData.sync(error);
|
||||||
if (error) {
|
if (error) {
|
||||||
panic("Could not sync {}", flashPath);
|
ircolib::panic("Could not sync {}", flashPath);
|
||||||
}
|
}
|
||||||
saveData.unmap();
|
saveData.unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto flashVec = ircolib::ReadFileBinary(flashPath);
|
auto flashVec = ircolib::read_file_binary(flashPath);
|
||||||
if (flashVec.empty()) {
|
if (flashVec.empty()) {
|
||||||
std::vector<u8> dummy{};
|
std::vector<u8> dummy{};
|
||||||
dummy.resize(FLASH_SIZE);
|
dummy.resize(FLASH_SIZE);
|
||||||
ircolib::WriteFileBinary(dummy, flashPath);
|
ircolib::write_file_binary(dummy, flashPath);
|
||||||
flashVec = ircolib::ReadFileBinary(flashPath);
|
flashVec = ircolib::read_file_binary(flashPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flashVec.size() != FLASH_SIZE) {
|
if (flashVec.size() != FLASH_SIZE) {
|
||||||
panic("Corrupt SRAM!");
|
ircolib::panic("Corrupt SRAM!");
|
||||||
}
|
}
|
||||||
|
|
||||||
saveData = mio::make_mmap_sink(flashPath, error);
|
saveData = mio::make_mmap_sink(flashPath, error);
|
||||||
if (error) {
|
if (error) {
|
||||||
panic("Could not make mmap {}", flashPath);
|
ircolib::panic("Could not make mmap {}", flashPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Flash::CommandExecute() const {
|
void Flash::CommandExecute() const {
|
||||||
trace("Flash::CommandExecute");
|
ircolib::trace("Flash::CommandExecute");
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case FlashState::Idle:
|
case FlashState::Idle:
|
||||||
break;
|
break;
|
||||||
@@ -63,7 +63,7 @@ void Flash::CommandExecute() const {
|
|||||||
saveData[eraseOffs + i] = 0xFF;
|
saveData[eraseOffs + i] = 0xFF;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic("Accessing flash when not mapped!");
|
ircolib::panic("Accessing flash when not mapped!");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FlashState::Write:
|
case FlashState::Write:
|
||||||
@@ -72,11 +72,11 @@ void Flash::CommandExecute() const {
|
|||||||
saveData[writeOffs + i] = writeBuf[i];
|
saveData[writeOffs + i] = writeBuf[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic("Accessing flash when not mapped!");
|
ircolib::panic("Accessing flash when not mapped!");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FlashState::Read:
|
case FlashState::Read:
|
||||||
panic("Execute command when flash in read state");
|
ircolib::panic("Execute command when flash in read state");
|
||||||
break;
|
break;
|
||||||
case FlashState::Status:
|
case FlashState::Status:
|
||||||
break;
|
break;
|
||||||
@@ -134,10 +134,10 @@ void Flash::Write<u32>(u32 index, u32 val) {
|
|||||||
CommandRead();
|
CommandRead();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
warn("Invalid flash command: {:02X}", cmd);
|
ircolib::warn("Invalid flash command: {:02X}", cmd);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn("Flash Write of {:08X} @ {:08X}", val, index);
|
ircolib::warn("Flash Write of {:08X} @ {:08X}", val, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,19 +145,19 @@ template <>
|
|||||||
void Flash::Write<u8>(u32 index, u8 val) {
|
void Flash::Write<u8>(u32 index, u8 val) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case FlashState::Idle:
|
case FlashState::Idle:
|
||||||
panic("Invalid FlashState::Idle with Write<u8>");
|
ircolib::panic("Invalid FlashState::Idle with Write<u8>");
|
||||||
case FlashState::Status:
|
case FlashState::Status:
|
||||||
panic("Invalid FlashState::Status with Write<u8>");
|
ircolib::panic("Invalid FlashState::Status with Write<u8>");
|
||||||
case FlashState::Erase:
|
case FlashState::Erase:
|
||||||
panic("Invalid FlashState::Erase with Write<u8>");
|
ircolib::panic("Invalid FlashState::Erase with Write<u8>");
|
||||||
case FlashState::Read:
|
case FlashState::Read:
|
||||||
panic("Invalid FlashState::Read with Write<u8>");
|
ircolib::panic("Invalid FlashState::Read with Write<u8>");
|
||||||
case FlashState::Write:
|
case FlashState::Write:
|
||||||
assert(index <= 0x7F && "Out of range flash Write8");
|
assert(index <= 0x7F && "Out of range flash Write8");
|
||||||
writeBuf[index] = val;
|
writeBuf[index] = val;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
warn("Invalid flash state on Write<u8>: {:02X}", static_cast<u8>(state));
|
ircolib::warn("Invalid flash state on Write<u8>: {:02X}", static_cast<u8>(state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,27 +165,27 @@ template <>
|
|||||||
u8 Flash::Read<u8>(const u32 index) const {
|
u8 Flash::Read<u8>(const u32 index) const {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case FlashState::Idle:
|
case FlashState::Idle:
|
||||||
panic("Flash read byte while in state FLASH_STATE_IDLE");
|
ircolib::panic("Flash read byte while in state FLASH_STATE_IDLE");
|
||||||
case FlashState::Write:
|
case FlashState::Write:
|
||||||
panic("Flash read byte while in state FLASH_STATE_WRITE");
|
ircolib::panic("Flash read byte while in state FLASH_STATE_WRITE");
|
||||||
case FlashState::Read:
|
case FlashState::Read:
|
||||||
if (saveData.is_mapped()) {
|
if (saveData.is_mapped()) {
|
||||||
const u8 value = saveData[index];
|
const u8 value = saveData[index];
|
||||||
trace("Flash read byte in state read: index {:08X} = {:02X}", index, value);
|
ircolib::trace("Flash read byte in state read: index {:08X} = {:02X}", index, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("Accessing flash when not mapped!");
|
ircolib::panic("Accessing flash when not mapped!");
|
||||||
|
|
||||||
case FlashState::Status:
|
case FlashState::Status:
|
||||||
{
|
{
|
||||||
const u32 offset = (7 - (index % 8)) * 8;
|
const u32 offset = (7 - (index % 8)) * 8;
|
||||||
const u8 value = (status >> offset) & 0xFF;
|
const u8 value = (status >> offset) & 0xFF;
|
||||||
trace("Flash read byte in state status: index {:08X} = {:02X}", index, value);
|
ircolib::trace("Flash read byte in state status: index {:08X} = {:02X}", index, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Flash read byte while in unknown state");
|
ircolib::panic("Flash read byte while in unknown state");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
static bool IsAddressMMIOorRDRAM(u32 addr) {
|
static bool IsAddressMMIOorRDRAM(u32 addr) {
|
||||||
if (ircolib::IsInsideRange(addr, RDRAM_REGION_START, RDRAM_REGION_END))
|
if (ircolib::is_inside_range(addr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(addr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::is_inside_range(addr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(addr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
ircolib::is_inside_range(addr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <Options.hpp>
|
#include <Options.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
@@ -76,7 +76,7 @@ void AI::Write(const u32 addr, const u32 val) {
|
|||||||
dac.precision = bitrate + 1;
|
dac.precision = bitrate + 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled AI write at addr {:08X} with val {:08X}", addr, val);
|
ircolib::panic("Unhandled AI write at addr {:08X} with val {:08X}", addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Audio.hpp>
|
#include <Audio.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
@@ -9,49 +9,49 @@ namespace n64 {
|
|||||||
#define BYTES_PER_HALF_SECOND (((float)AUDIO_SAMPLE_RATE / 2) * SYSTEM_SAMPLE_SIZE)
|
#define BYTES_PER_HALF_SECOND (((float)AUDIO_SAMPLE_RATE / 2) * SYSTEM_SAMPLE_SIZE)
|
||||||
|
|
||||||
AudioDevice::AudioDevice() {
|
AudioDevice::AudioDevice() {
|
||||||
audioStreamMutex = SDL_CreateMutex();
|
audioStreamMutex = SDL_CreateMutex();
|
||||||
if (!audioStreamMutex) {
|
if (!audioStreamMutex) {
|
||||||
panic("Unable to initialize audio mutex: {}", SDL_GetError());
|
ircolib::panic("Unable to initialize audio mutex: {}", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||||
request = {SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE};
|
request = {SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE};
|
||||||
|
|
||||||
audioStream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &request, nullptr, nullptr);
|
audioStream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &request, nullptr, nullptr);
|
||||||
if (!audioStream) {
|
if (!audioStream) {
|
||||||
panic("Unable to create audio stream: {}", SDL_GetError());
|
ircolib::panic("Unable to create audio stream: {}", SDL_GetError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDevice::PushSample(const float left, const float volumeL, const float right, const float volumeR) {
|
void AudioDevice::PushSample(const float left, const float volumeL, const float right, const float volumeR) {
|
||||||
const float adjustedL = left * volumeL;
|
const float adjustedL = left * volumeL;
|
||||||
const float adjustedR = right * volumeR;
|
const float adjustedR = right * volumeR;
|
||||||
const float samples[]{adjustedL, adjustedR};
|
const float samples[]{adjustedL, adjustedR};
|
||||||
|
|
||||||
if (const auto availableBytes = static_cast<float>(SDL_GetAudioStreamAvailable(audioStream));
|
if (const auto availableBytes = static_cast<float>(SDL_GetAudioStreamAvailable(audioStream));
|
||||||
availableBytes <= BYTES_PER_HALF_SECOND) {
|
availableBytes <= BYTES_PER_HALF_SECOND) {
|
||||||
SDL_PutAudioStreamData(audioStream, samples, 2 * SYSTEM_SAMPLE_SIZE);
|
SDL_PutAudioStreamData(audioStream, samples, 2 * SYSTEM_SAMPLE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!running) {
|
if (!running) {
|
||||||
SDL_ResumeAudioStreamDevice(audioStream);
|
SDL_ResumeAudioStreamDevice(audioStream);
|
||||||
running = true;
|
running = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDevice::AdjustSampleRate(int sampleRate) {
|
void AudioDevice::AdjustSampleRate(int sampleRate) {
|
||||||
LockMutex();
|
LockMutex();
|
||||||
SDL_DestroyAudioStream(audioStream);
|
SDL_DestroyAudioStream(audioStream);
|
||||||
|
|
||||||
if (sampleRate < 4000) { // hack for Animal Forest. It requests a frequency of 3000-something. Weird asf
|
if (sampleRate < 4000) { // hack for Animal Forest. It requests a frequency of 3000-something. Weird asf
|
||||||
sampleRate *= 4000.f / static_cast<float>(sampleRate);
|
sampleRate *= 4000.f / static_cast<float>(sampleRate);
|
||||||
}
|
}
|
||||||
request = {SYSTEM_SAMPLE_FORMAT, 2, sampleRate};
|
request = {SYSTEM_SAMPLE_FORMAT, 2, sampleRate};
|
||||||
|
|
||||||
audioStream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &request, nullptr, nullptr);
|
audioStream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &request, nullptr, nullptr);
|
||||||
if (!audioStream) {
|
if (!audioStream) {
|
||||||
panic("Unable to create audio stream: {}", SDL_GetError());
|
ircolib::panic("Unable to create audio stream: {}", SDL_GetError());
|
||||||
}
|
}
|
||||||
UnlockMutex();
|
UnlockMutex();
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <core/mmio/MI.hpp>
|
#include <core/mmio/MI.hpp>
|
||||||
#include <core/registers/Registers.hpp>
|
#include <core/registers/Registers.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
#define MI_VERSION_REG 0x02020102
|
#define MI_VERSION_REG 0x02020102
|
||||||
|
|
||||||
@@ -8,58 +8,58 @@ namespace n64 {
|
|||||||
MI::MI() { Reset(); }
|
MI::MI() { Reset(); }
|
||||||
|
|
||||||
void MI::Reset() {
|
void MI::Reset() {
|
||||||
intrMask.raw = 0;
|
intrMask.raw = 0;
|
||||||
intr.raw = 0;
|
intr.raw = 0;
|
||||||
mode.raw = 0;
|
mode.raw = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MI::Read(u32 paddr) const -> u32 {
|
auto MI::Read(u32 paddr) const -> u32 {
|
||||||
switch (paddr & 0xF) {
|
switch (paddr & 0xF) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
return mode.raw & 0x3FF;
|
return mode.raw & 0x3FF;
|
||||||
case 0x4:
|
case 0x4:
|
||||||
return MI_VERSION_REG;
|
return MI_VERSION_REG;
|
||||||
case 0x8:
|
case 0x8:
|
||||||
return intr.raw & 0x3F;
|
return intr.raw & 0x3F;
|
||||||
case 0xC:
|
case 0xC:
|
||||||
return intrMask.raw & 0x3F;
|
return intrMask.raw & 0x3F;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled MI[{:08X}] read", paddr);
|
ircolib::panic("Unhandled MI[{:08X}] read", paddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MI::Write(u32 paddr, u32 val) {
|
void MI::Write(u32 paddr, u32 val) {
|
||||||
switch (paddr & 0xF) { //-----------sc-cscs-cvvv-vvvv
|
switch (paddr & 0xF) { //-----------sc-cscs-cvvv-vvvv
|
||||||
case 0x0: // ----|----|----|----|--uu|deer|rccc|cccc
|
case 0x0: // ----|----|----|----|--uu|deer|rccc|cccc
|
||||||
mode.repeatCount = val & 0x7F;
|
mode.repeatCount = val & 0x7F;
|
||||||
mode.repeat = val & 0x100 ? 1 : val & 0x80 ? 0 : mode.repeat;
|
mode.repeat = val & 0x100 ? 1 : val & 0x80 ? 0 : mode.repeat;
|
||||||
mode.ebus = val & 0x400 ? 1 : val & 0x200 ? 0 : mode.ebus;
|
mode.ebus = val & 0x400 ? 1 : val & 0x200 ? 0 : mode.ebus;
|
||||||
mode.upper = val & 0x2000 ? 1 : val & 0x1000 ? 0 : mode.upper;
|
mode.upper = val & 0x2000 ? 1 : val & 0x1000 ? 0 : mode.upper;
|
||||||
if(val & 0x800) {
|
if (val & 0x800) {
|
||||||
InterruptLower(Interrupt::DP);
|
InterruptLower(Interrupt::DP);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
case 0x8:
|
||||||
|
break;
|
||||||
|
case 0xC:
|
||||||
|
for (int bit = 0; bit < 6; bit++) {
|
||||||
|
const int clearbit = bit << 1;
|
||||||
|
const int setbit = (bit << 1) + 1;
|
||||||
|
|
||||||
|
if (val & (1 << clearbit)) {
|
||||||
|
intrMask.raw &= ~(1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << setbit)) {
|
||||||
|
intrMask.raw |= 1 << bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateInterrupt();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ircolib::panic("Unhandled MI write @ 0x{:08X} with value 0x{:08X}", paddr, val);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 0x4:
|
|
||||||
case 0x8:
|
|
||||||
break;
|
|
||||||
case 0xC:
|
|
||||||
for (int bit = 0; bit < 6; bit++) {
|
|
||||||
const int clearbit = bit << 1;
|
|
||||||
const int setbit = (bit << 1) + 1;
|
|
||||||
|
|
||||||
if (val & (1 << clearbit)) {
|
|
||||||
intrMask.raw &= ~(1 << bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val & (1 << setbit)) {
|
|
||||||
intrMask.raw |= 1 << bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateInterrupt();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Unhandled MI write @ 0x{:08X} with value 0x{:08X}", paddr, val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
+131
-98
@@ -2,7 +2,7 @@
|
|||||||
#include <Scheduler.hpp>
|
#include <Scheduler.hpp>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <core/mmio/PI.hpp>
|
#include <core/mmio/PI.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
PI::PI() { Reset(); }
|
PI::PI() { Reset(); }
|
||||||
@@ -52,17 +52,20 @@ auto PI::BusRead<u8, true>(u32 addr) -> u8 {
|
|||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
mem.DumpRDRAM();
|
mem.DumpRDRAM();
|
||||||
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
ircolib::panic(
|
||||||
"returning FF because it is not emulated (pc: 0x{:016X})",
|
"Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
||||||
addr, (u64)Core::GetRegs().oldPC);
|
"returning FF because it is not emulated (pc: 0x{:016X})",
|
||||||
|
addr, (u64)Core::GetRegs().oldPC);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
ircolib::panic(
|
||||||
"returning FF because it is not emulated",
|
"Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, "
|
ircolib::warn(
|
||||||
"returning FF because it is not emulated",
|
"Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
return mem.BackupRead<u8>(addr - SREGION_PI_SRAM);
|
return mem.BackupRead<u8>(addr - SREGION_PI_SRAM);
|
||||||
@@ -71,14 +74,16 @@ auto PI::BusRead<u8, true>(u32 addr) -> u8 {
|
|||||||
// round to nearest 4 byte boundary, keeping old LSB
|
// round to nearest 4 byte boundary, keeping old LSB
|
||||||
const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||||
if (index >= mem.rom.cart.size()) {
|
if (index >= mem.rom.cart.size()) {
|
||||||
warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr,
|
ircolib::warn(
|
||||||
index, index, mem.rom.cart.size(), mem.rom.cart.size());
|
"Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr,
|
||||||
|
index, index, mem.rom.cart.size(), mem.rom.cart.size());
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
return mem.rom.cart[index];
|
return mem.rom.cart[index];
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,17 +96,20 @@ auto PI::BusRead<u8, false>(u32 addr) -> u8 {
|
|||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
ircolib::panic(
|
||||||
"returning FF because it is not emulated",
|
"Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
ircolib::panic(
|
||||||
"returning FF because it is not emulated",
|
"Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, "
|
ircolib::warn(
|
||||||
"returning FF because it is not emulated",
|
"Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
return mem.BackupRead<u8>(addr - SREGION_PI_SRAM);
|
return mem.BackupRead<u8>(addr - SREGION_PI_SRAM);
|
||||||
@@ -111,14 +119,16 @@ auto PI::BusRead<u8, false>(u32 addr) -> u8 {
|
|||||||
// round to nearest 4 byte boundary, keeping old LSB
|
// round to nearest 4 byte boundary, keeping old LSB
|
||||||
const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||||
if (index >= mem.rom.cart.size()) {
|
if (index >= mem.rom.cart.size()) {
|
||||||
warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr,
|
ircolib::warn(
|
||||||
index, index, mem.rom.cart.size(), mem.rom.cart.size());
|
"Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr,
|
||||||
|
index, index, mem.rom.cart.size(), mem.rom.cart.size());
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
return mem.rom.cart[index];
|
return mem.rom.cart[index];
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,25 +137,28 @@ void PI::BusWrite<u8, true>(u32 addr, u32 val) {
|
|||||||
n64::Mem &mem = n64::Core::GetMem();
|
n64::Mem &mem = n64::Core::GetMem();
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
ircolib::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
if (addr == 0x05000020) {
|
if (addr == 0x05000020) {
|
||||||
fprintf(stderr, "%c", val);
|
fprintf(stderr, "%c", val);
|
||||||
} else {
|
} else {
|
||||||
warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!",
|
ircolib::warn(
|
||||||
val, addr);
|
"Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!",
|
||||||
|
val, addr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
ircolib::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val,
|
||||||
|
addr);
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
mem.BackupWrite<u8>(addr - SREGION_PI_SRAM, val);
|
mem.BackupWrite<u8>(addr - SREGION_PI_SRAM, val);
|
||||||
break;
|
break;
|
||||||
case REGION_PI_ROM:
|
case REGION_PI_ROM:
|
||||||
warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
ircolib::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,31 +182,35 @@ auto PI::BusRead<u16, false>(u32 addr) -> u16 {
|
|||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
ircolib::panic(
|
||||||
"returning FF because it is not emulated",
|
"Reading half from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
ircolib::panic(
|
||||||
"returning FF because it is not emulated",
|
"Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, "
|
ircolib::panic(
|
||||||
"returning FF because it is not emulated",
|
"Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
|
ircolib::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
|
||||||
case REGION_PI_ROM:
|
case REGION_PI_ROM:
|
||||||
{
|
{
|
||||||
addr = (addr + 2) & ~3;
|
addr = (addr + 2) & ~3;
|
||||||
const u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM;
|
const u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM;
|
||||||
if (index > mem.rom.cart.size() - 1) {
|
if (index > mem.rom.cart.size() - 1) {
|
||||||
panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index,
|
ircolib::panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr,
|
||||||
index);
|
index, index);
|
||||||
}
|
}
|
||||||
return ircolib::ReadAccess<u16>(mem.rom.cart, index);
|
return ircolib::read_access<u16>(mem.rom.cart, index);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,19 +227,22 @@ void PI::BusWrite<u16, false>(u32 addr, u32 val) {
|
|||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
ircolib::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
panic("Writing half 0x{:04X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!",
|
ircolib::panic(
|
||||||
val, addr);
|
"Writing half 0x{:04X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val,
|
||||||
|
addr);
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
ircolib::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val,
|
||||||
|
addr);
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr);
|
ircolib::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr);
|
||||||
case REGION_PI_ROM:
|
case REGION_PI_ROM:
|
||||||
warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
ircolib::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,19 +260,22 @@ auto PI::BusRead<u32, false>(u32 addr) -> u32 {
|
|||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
ircolib::warn(
|
||||||
"returning FF because it is not emulated",
|
"Reading word from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
ircolib::warn(
|
||||||
"returning FF because it is not emulated",
|
"Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, "
|
ircolib::warn(
|
||||||
"returning FF because it is not emulated",
|
"Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, "
|
||||||
addr);
|
"returning FF because it is not emulated",
|
||||||
|
addr);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
return mem.BackupRead<u32>(addr);
|
return mem.BackupRead<u32>(addr);
|
||||||
@@ -263,20 +286,22 @@ auto PI::BusRead<u32, false>(u32 addr) -> u32 {
|
|||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_CART_ISVIEWER_BUFFER:
|
case REGION_CART_ISVIEWER_BUFFER:
|
||||||
return std::byteswap<u32>(
|
return std::byteswap<u32>(
|
||||||
ircolib::ReadAccess<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER));
|
ircolib::read_access<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER));
|
||||||
case CART_ISVIEWER_FLUSH:
|
case CART_ISVIEWER_FLUSH:
|
||||||
panic("Read from ISViewer flush!");
|
ircolib::panic("Read from ISViewer flush!");
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index);
|
ircolib::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr,
|
||||||
|
index, index);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ircolib::ReadAccess<u32>(mem.rom.cart, index);
|
return ircolib::read_access<u32>(mem.rom.cart, index);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,20 +318,21 @@ void PI::BusWrite<u32, false>(u32 addr, u32 val) {
|
|||||||
if (!WriteLatch(val)) [[unlikely]] {
|
if (!WriteLatch(val)) [[unlikely]] {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||||
return;
|
return;
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
if (!WriteLatch(val)) [[unlikely]] {
|
if (!WriteLatch(val)) [[unlikely]] {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
warn("Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!",
|
ircolib::warn(
|
||||||
val, addr);
|
"Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val,
|
||||||
|
addr);
|
||||||
return;
|
return;
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
if (!WriteLatch(val)) [[unlikely]] {
|
if (!WriteLatch(val)) [[unlikely]] {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
||||||
return;
|
return;
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
if (!WriteLatch(val)) [[unlikely]] {
|
if (!WriteLatch(val)) [[unlikely]] {
|
||||||
@@ -317,7 +343,7 @@ void PI::BusWrite<u32, false>(u32 addr, u32 val) {
|
|||||||
case REGION_PI_ROM:
|
case REGION_PI_ROM:
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_CART_ISVIEWER_BUFFER:
|
case REGION_CART_ISVIEWER_BUFFER:
|
||||||
ircolib::WriteAccess<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, std::byteswap(val));
|
ircolib::write_access<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, std::byteswap(val));
|
||||||
break;
|
break;
|
||||||
case CART_ISVIEWER_FLUSH:
|
case CART_ISVIEWER_FLUSH:
|
||||||
{
|
{
|
||||||
@@ -327,21 +353,23 @@ void PI::BusWrite<u32, false>(u32 addr, u32 val) {
|
|||||||
mem.isviewer_sink << message;
|
mem.isviewer_sink << message;
|
||||||
mem.isviewer_sink.flush();
|
mem.isviewer_sink.flush();
|
||||||
} else {
|
} else {
|
||||||
panic("ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!",
|
ircolib::panic(
|
||||||
CART_ISVIEWER_SIZE, val);
|
"ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!",
|
||||||
|
CART_ISVIEWER_SIZE, val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if (!WriteLatch(val)) [[unlikely]] {
|
if (!WriteLatch(val)) [[unlikely]] {
|
||||||
warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM");
|
ircolib::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,24 +387,25 @@ auto PI::BusRead<u64, false>(u32 addr) -> u64 {
|
|||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", addr);
|
ircolib::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", addr);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", addr);
|
ircolib::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", addr);
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", addr);
|
ircolib::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", addr);
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
|
ircolib::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
|
||||||
case REGION_PI_ROM:
|
case REGION_PI_ROM:
|
||||||
{
|
{
|
||||||
const u32 index = addr - SREGION_PI_ROM;
|
const u32 index = addr - SREGION_PI_ROM;
|
||||||
if (index > mem.rom.cart.size() - 7) { // -7 because we're reading an entire dword
|
if (index > mem.rom.cart.size() - 7) { // -7 because we're reading an entire dword
|
||||||
panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index,
|
ircolib::panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr,
|
||||||
index);
|
index, index);
|
||||||
}
|
}
|
||||||
return ircolib::ReadAccess<u64>(mem.rom.cart, index);
|
return ircolib::read_access<u64>(mem.rom.cart, index);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,18 +422,22 @@ void PI::BusWrite<false>(u32 addr, u64 val) {
|
|||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
ircolib::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val,
|
||||||
|
addr);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", val, addr);
|
ircolib::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", val,
|
||||||
|
addr);
|
||||||
case REGION_PI_64DD_ROM:
|
case REGION_PI_64DD_ROM:
|
||||||
panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
ircolib::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val,
|
||||||
|
addr);
|
||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr);
|
ircolib::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr);
|
||||||
case REGION_PI_ROM:
|
case REGION_PI_ROM:
|
||||||
warn("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
ircolib::warn("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
ircolib::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +484,7 @@ auto PI::Read(u32 addr) const -> u32 {
|
|||||||
case 0x04600030:
|
case 0x04600030:
|
||||||
return piBsdDom2Rls;
|
return piBsdDom2Rls;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled PI[{:08X}] read", addr);
|
ircolib::panic("Unhandled PI[{:08X}] read", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +498,7 @@ u8 PI::GetDomain(const u32 address) {
|
|||||||
case REGION_PI_SRAM:
|
case REGION_PI_SRAM:
|
||||||
return 2;
|
return 2;
|
||||||
default:
|
default:
|
||||||
panic("Unknown PI domain for address {:08X}!", address);
|
ircolib::panic("Unknown PI domain for address {:08X}!", address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +523,7 @@ u32 PI::AccessTiming(const u8 domain, const u32 length) const {
|
|||||||
page_size = 1 << (piBsdDom2Pgs + 2);
|
page_size = 1 << (piBsdDom2Pgs + 2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unknown PI domain: {}\n", domain);
|
ircolib::panic("Unknown PI domain: {}\n", domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t pages = static_cast<uint32_t>(ceil(static_cast<double>(length) / static_cast<double>(page_size)));
|
const uint32_t pages = static_cast<uint32_t>(ceil(static_cast<double>(length) / static_cast<double>(page_size)));
|
||||||
@@ -506,7 +539,7 @@ template <>
|
|||||||
void PI::DMA<false>() {
|
void PI::DMA<false>() {
|
||||||
n64::Mem &mem = n64::Core::GetMem();
|
n64::Mem &mem = n64::Core::GetMem();
|
||||||
const s32 len = rdLen + 1;
|
const s32 len = rdLen + 1;
|
||||||
trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
ircolib::trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
||||||
if (mem.rom.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < (CART_REGION_START_2_2 + 1_mb)) {
|
if (mem.rom.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < (CART_REGION_START_2_2 + 1_mb)) {
|
||||||
cartAddr = SREGION_PI_SRAM | ((cartAddr & (1_mb - 1)) << 1);
|
cartAddr = SREGION_PI_SRAM | ((cartAddr & (1_mb - 1)) << 1);
|
||||||
}
|
}
|
||||||
@@ -524,7 +557,7 @@ void PI::DMA<false>() {
|
|||||||
dmaBusy = true;
|
dmaBusy = true;
|
||||||
|
|
||||||
u64 completo = AccessTiming(GetDomain(cartAddr), len);
|
u64 completo = AccessTiming(GetDomain(cartAddr), len);
|
||||||
trace("Will complete in {} cycles", completo);
|
ircolib::trace("Will complete in {} cycles", completo);
|
||||||
Scheduler::GetInstance().EnqueueRelative(completo, PI_DMA_COMPLETE);
|
Scheduler::GetInstance().EnqueueRelative(completo, PI_DMA_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +566,7 @@ template <>
|
|||||||
void PI::DMA<true>() {
|
void PI::DMA<true>() {
|
||||||
n64::Mem &mem = n64::Core::GetMem();
|
n64::Mem &mem = n64::Core::GetMem();
|
||||||
const s32 len = wrLen + 1;
|
const s32 len = wrLen + 1;
|
||||||
trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
|
ircolib::trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
|
||||||
|
|
||||||
if (mem.rom.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < (CART_REGION_START_2_2 + 1_mb)) {
|
if (mem.rom.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < (CART_REGION_START_2_2 + 1_mb)) {
|
||||||
cartAddr = SREGION_PI_SRAM | ((cartAddr & (1_mb - 1)) << 1);
|
cartAddr = SREGION_PI_SRAM | ((cartAddr & (1_mb - 1)) << 1);
|
||||||
@@ -551,7 +584,7 @@ void PI::DMA<true>() {
|
|||||||
|
|
||||||
dmaBusy = true;
|
dmaBusy = true;
|
||||||
u64 completo = AccessTiming(GetDomain(cartAddr), len);
|
u64 completo = AccessTiming(GetDomain(cartAddr), len);
|
||||||
trace("Will complete in {} cycles", completo);
|
ircolib::trace("Will complete in {} cycles", completo);
|
||||||
Scheduler::GetInstance().EnqueueRelative(completo, PI_DMA_COMPLETE);
|
Scheduler::GetInstance().EnqueueRelative(completo, PI_DMA_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,7 +636,7 @@ void PI::Write(u32 addr, u32 val) {
|
|||||||
piBsdDom2Rls = val & 0xff;
|
piBsdDom2Rls = val & 0xff;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled PI[{:08X}] write ({:08X})", val, addr);
|
ircolib::panic("Unhandled PI[{:08X}] write ({:08X})", val, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cic_nus_6105/n64_cic_nus_6105.hpp>
|
#include <cic_nus_6105/n64_cic_nus_6105.hpp>
|
||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <Options.hpp>
|
#include <Options.hpp>
|
||||||
|
|
||||||
#define MEMPAK_SIZE 32768
|
#define MEMPAK_SIZE 32768
|
||||||
@@ -17,14 +17,14 @@ void PIF::Reset() {
|
|||||||
if (mempak.is_mapped()) {
|
if (mempak.is_mapped()) {
|
||||||
mempak.sync(error);
|
mempak.sync(error);
|
||||||
if (error) {
|
if (error) {
|
||||||
panic("Could not sync {}", mempakPath);
|
ircolib::panic("Could not sync {}", mempakPath);
|
||||||
}
|
}
|
||||||
mempak.unmap();
|
mempak.unmap();
|
||||||
}
|
}
|
||||||
if (eeprom.is_mapped()) {
|
if (eeprom.is_mapped()) {
|
||||||
eeprom.sync(error);
|
eeprom.sync(error);
|
||||||
if (error) {
|
if (error) {
|
||||||
panic("Could not sync {}", eepromPath);
|
ircolib::panic("Could not sync {}", eepromPath);
|
||||||
}
|
}
|
||||||
eeprom.unmap();
|
eeprom.unmap();
|
||||||
}
|
}
|
||||||
@@ -48,25 +48,25 @@ void PIF::MaybeLoadMempak() {
|
|||||||
if (mempak.is_mapped()) {
|
if (mempak.is_mapped()) {
|
||||||
mempak.sync(error);
|
mempak.sync(error);
|
||||||
if (error) {
|
if (error) {
|
||||||
panic("Could not sync {}", mempakPath);
|
ircolib::panic("Could not sync {}", mempakPath);
|
||||||
}
|
}
|
||||||
mempak.unmap();
|
mempak.unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mempakVec = ircolib::ReadFileBinary(mempakPath);
|
auto mempakVec = ircolib::read_file_binary(mempakPath);
|
||||||
if (mempak.empty()) {
|
if (mempak.empty()) {
|
||||||
info(R"(Empty mempak, making one @ "{}" ...)", mempakPath);
|
ircolib::info(R"(Empty mempak, making one @ "{}" ...)", mempakPath);
|
||||||
ircolib::WriteFileBinary(std::array<u8, MEMPAK_SIZE>{}, mempakPath);
|
ircolib::write_file_binary(std::array<u8, MEMPAK_SIZE>{}, mempakPath);
|
||||||
mempakVec = ircolib::ReadFileBinary(mempakPath);
|
mempakVec = ircolib::read_file_binary(mempakPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mempakVec.size() != MEMPAK_SIZE) {
|
if (mempakVec.size() != MEMPAK_SIZE) {
|
||||||
panic("Corrupt mempak!");
|
ircolib::panic("Corrupt mempak!");
|
||||||
}
|
}
|
||||||
|
|
||||||
mempak = mio::make_mmap_sink(mempakPath, error);
|
mempak = mio::make_mmap_sink(mempakPath, error);
|
||||||
if (error) {
|
if (error) {
|
||||||
panic("Could not open {}", mempakPath);
|
ircolib::panic("Could not open {}", mempakPath);
|
||||||
}
|
}
|
||||||
mempakOpen = true;
|
mempakOpen = true;
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ FORCE_INLINE size_t GetSaveSize(SaveType saveType) {
|
|||||||
case SAVE_FLASH_1m:
|
case SAVE_FLASH_1m:
|
||||||
return 131072;
|
return 131072;
|
||||||
default:
|
default:
|
||||||
panic("Unknown save type!");
|
ircolib::panic("Unknown save type!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,28 +101,28 @@ void PIF::LoadEeprom(const SaveType saveType, const std::string &path) {
|
|||||||
if (eeprom.is_mapped()) {
|
if (eeprom.is_mapped()) {
|
||||||
eeprom.sync(error);
|
eeprom.sync(error);
|
||||||
if (error) {
|
if (error) {
|
||||||
panic("Could not sync {}", eepromPath);
|
ircolib::panic("Could not sync {}", eepromPath);
|
||||||
}
|
}
|
||||||
eeprom.unmap();
|
eeprom.unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
eepromSize = GetSaveSize(saveType);
|
eepromSize = GetSaveSize(saveType);
|
||||||
|
|
||||||
auto eepromVec = ircolib::ReadFileBinary(eepromPath);
|
auto eepromVec = ircolib::read_file_binary(eepromPath);
|
||||||
if (eepromVec.empty()) {
|
if (eepromVec.empty()) {
|
||||||
std::vector<u8> dummy{};
|
std::vector<u8> dummy{};
|
||||||
dummy.resize(GetSaveSize(saveType));
|
dummy.resize(GetSaveSize(saveType));
|
||||||
ircolib::WriteFileBinary(dummy, eepromPath);
|
ircolib::write_file_binary(dummy, eepromPath);
|
||||||
eepromVec = dummy;
|
eepromVec = dummy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eepromVec.size() != eepromSize) {
|
if (eepromVec.size() != eepromSize) {
|
||||||
panic("Corrupt eeprom!");
|
ircolib::panic("Corrupt eeprom!");
|
||||||
}
|
}
|
||||||
|
|
||||||
eeprom = mio::make_mmap_sink(eepromPath, error);
|
eeprom = mio::make_mmap_sink(eepromPath, error);
|
||||||
if (error) {
|
if (error) {
|
||||||
panic("Could not open {}. Reason {}", eepromPath, error.message());
|
ircolib::panic("Could not open {}. Reason {}", eepromPath, error.message());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +254,7 @@ void PIF::ConfigureJoyBusFrame() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Invalid read RTC block {}", commandStart);
|
ircolib::panic("Invalid read RTC block {}", commandStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -262,7 +262,7 @@ void PIF::ConfigureJoyBusFrame() {
|
|||||||
memset(res, 0, 8);
|
memset(res, 0, 8);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Invalid PIF command: {:X}", commandIndex);
|
ircolib::panic("Invalid PIF command: {:X}", commandIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
i += commandLength + reslen;
|
i += commandLength + reslen;
|
||||||
@@ -351,12 +351,12 @@ void PIF::EepromRead(const u8 *cmd, u8 *res) const {
|
|||||||
if (channel == 4) {
|
if (channel == 4) {
|
||||||
const u8 offset = cmd[3];
|
const u8 offset = cmd[3];
|
||||||
if ((offset * 8) >= GetSaveSize(mem.rom.saveType)) {
|
if ((offset * 8) >= GetSaveSize(mem.rom.saveType)) {
|
||||||
panic("Out of range EEPROM read! offset: {:02X}", offset);
|
ircolib::panic("Out of range EEPROM read! offset: {:02X}", offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy_n(eeprom.begin() + offset * 8, 8, res);
|
std::copy_n(eeprom.begin() + offset * 8, 8, res);
|
||||||
} else {
|
} else {
|
||||||
panic("EEPROM read on bad channel {}", channel);
|
ircolib::panic("EEPROM read on bad channel {}", channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,14 +366,14 @@ void PIF::EepromWrite(const u8 *cmd, u8 *res) {
|
|||||||
if (channel == 4) {
|
if (channel == 4) {
|
||||||
const u8 offset = cmd[3];
|
const u8 offset = cmd[3];
|
||||||
if ((offset * 8) >= GetSaveSize(mem.rom.saveType)) {
|
if ((offset * 8) >= GetSaveSize(mem.rom.saveType)) {
|
||||||
panic("Out of range EEPROM write! offset: {:02X}", offset);
|
ircolib::panic("Out of range EEPROM write! offset: {:02X}", offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy_n(cmd + 4, 8, eeprom.begin() + offset * 8);
|
std::copy_n(cmd + 4, 8, eeprom.begin() + offset * 8);
|
||||||
|
|
||||||
res[0] = 0; // Error byte, I guess it always succeeds?
|
res[0] = 0; // Error byte, I guess it always succeeds?
|
||||||
} else {
|
} else {
|
||||||
panic("EEPROM write on bad channel {}", channel);
|
ircolib::panic("EEPROM write on bad channel {}", channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ void PIF::HLE(const bool pal, const CICType cicType) const {
|
|||||||
|
|
||||||
switch (cicType) {
|
switch (cicType) {
|
||||||
case UNKNOWN_CIC_TYPE:
|
case UNKNOWN_CIC_TYPE:
|
||||||
warn("Unknown CIC type!");
|
ircolib::warn("Unknown CIC type!");
|
||||||
break;
|
break;
|
||||||
case CIC_NUS_6101:
|
case CIC_NUS_6101:
|
||||||
regs.Write<u64>(0, 0x0000000000000000);
|
regs.Write<u64>(0, 0x0000000000000000);
|
||||||
@@ -651,7 +651,7 @@ void PIF::Execute() const {
|
|||||||
mem.Write<u32>(PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
|
mem.Write<u32>(PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
|
||||||
switch (cicType) {
|
switch (cicType) {
|
||||||
case UNKNOWN_CIC_TYPE:
|
case UNKNOWN_CIC_TYPE:
|
||||||
warn("Unknown CIC type!");
|
ircolib::warn("Unknown CIC type!");
|
||||||
break;
|
break;
|
||||||
case CIC_NUS_6101 ... CIC_NUS_6103_7103:
|
case CIC_NUS_6101 ... CIC_NUS_6103_7103:
|
||||||
mem.Write<u32>(0x318, RDRAM_SIZE);
|
mem.Write<u32>(0x318, RDRAM_SIZE);
|
||||||
|
|||||||
@@ -1,121 +1,121 @@
|
|||||||
#include <Netplay.hpp>
|
#include <Netplay.hpp>
|
||||||
#include <PIF.hpp>
|
#include <PIF.hpp>
|
||||||
#include <PIF/MupenMovie.hpp>
|
#include <PIF/MupenMovie.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void PIF::InitDevices(SaveType saveType) {
|
void PIF::InitDevices(SaveType saveType) {
|
||||||
joybusDevices[0].type = JOYBUS_CONTROLLER;
|
joybusDevices[0].type = JOYBUS_CONTROLLER;
|
||||||
joybusDevices[0].accessoryType = ACCESSORY_MEMPACK;
|
joybusDevices[0].accessoryType = ACCESSORY_MEMPACK;
|
||||||
for (int i = 1; i < 4; i++) { // TODO: make this configurable
|
for (int i = 1; i < 4; i++) { // TODO: make this configurable
|
||||||
joybusDevices[i].type = JOYBUS_NONE;
|
joybusDevices[i].type = JOYBUS_NONE;
|
||||||
joybusDevices[i].accessoryType = ACCESSORY_NONE;
|
joybusDevices[i].accessoryType = ACCESSORY_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saveType == SAVE_EEPROM_4k) {
|
if (saveType == SAVE_EEPROM_4k) {
|
||||||
joybusDevices[4].type = JOYBUS_4KB_EEPROM;
|
joybusDevices[4].type = JOYBUS_4KB_EEPROM;
|
||||||
} else if (saveType == SAVE_EEPROM_16k) {
|
} else if (saveType == SAVE_EEPROM_16k) {
|
||||||
joybusDevices[4].type = JOYBUS_16KB_EEPROM;
|
joybusDevices[4].type = JOYBUS_16KB_EEPROM;
|
||||||
} else {
|
} else {
|
||||||
joybusDevices[4].type = JOYBUS_NONE;
|
joybusDevices[4].type = JOYBUS_NONE;
|
||||||
}
|
}
|
||||||
joybusDevices[5].type = JOYBUS_NONE;
|
joybusDevices[5].type = JOYBUS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PIF::ControllerID(u8 *res) const {
|
void PIF::ControllerID(u8 *res) const {
|
||||||
if (channel < 6) {
|
if (channel < 6) {
|
||||||
switch (joybusDevices[channel].type) {
|
switch (joybusDevices[channel].type) {
|
||||||
case JOYBUS_NONE:
|
case JOYBUS_NONE:
|
||||||
res[0] = 0x00;
|
res[0] = 0x00;
|
||||||
res[1] = 0x00;
|
res[1] = 0x00;
|
||||||
res[2] = 0x00;
|
res[2] = 0x00;
|
||||||
break;
|
break;
|
||||||
case JOYBUS_CONTROLLER:
|
case JOYBUS_CONTROLLER:
|
||||||
res[0] = 0x05;
|
res[0] = 0x05;
|
||||||
res[1] = 0x00;
|
res[1] = 0x00;
|
||||||
res[2] = joybusDevices[channel].accessoryType != ACCESSORY_NONE ? 0x01 : 0x02;
|
res[2] = joybusDevices[channel].accessoryType != ACCESSORY_NONE ? 0x01 : 0x02;
|
||||||
break;
|
break;
|
||||||
case JOYBUS_DANCEPAD:
|
case JOYBUS_DANCEPAD:
|
||||||
res[0] = 0x05;
|
res[0] = 0x05;
|
||||||
res[1] = 0x00;
|
res[1] = 0x00;
|
||||||
res[2] = 0x00;
|
res[2] = 0x00;
|
||||||
break;
|
break;
|
||||||
case JOYBUS_VRU:
|
case JOYBUS_VRU:
|
||||||
res[0] = 0x00;
|
res[0] = 0x00;
|
||||||
res[1] = 0x01;
|
res[1] = 0x01;
|
||||||
res[2] = 0x00;
|
res[2] = 0x00;
|
||||||
break;
|
break;
|
||||||
case JOYBUS_MOUSE:
|
case JOYBUS_MOUSE:
|
||||||
res[0] = 0x02;
|
res[0] = 0x02;
|
||||||
res[1] = 0x00;
|
res[1] = 0x00;
|
||||||
res[2] = 0x00;
|
res[2] = 0x00;
|
||||||
break;
|
break;
|
||||||
case JOYBUS_RANDNET_KEYBOARD:
|
case JOYBUS_RANDNET_KEYBOARD:
|
||||||
res[0] = 0x00;
|
res[0] = 0x00;
|
||||||
res[1] = 0x02;
|
res[1] = 0x02;
|
||||||
res[2] = 0x00;
|
res[2] = 0x00;
|
||||||
break;
|
break;
|
||||||
case JOYBUS_DENSHA_DE_GO:
|
case JOYBUS_DENSHA_DE_GO:
|
||||||
res[0] = 0x20;
|
res[0] = 0x20;
|
||||||
res[1] = 0x04;
|
res[1] = 0x04;
|
||||||
res[2] = 0x00;
|
res[2] = 0x00;
|
||||||
break;
|
break;
|
||||||
case JOYBUS_4KB_EEPROM:
|
case JOYBUS_4KB_EEPROM:
|
||||||
res[0] = 0x00;
|
res[0] = 0x00;
|
||||||
res[1] = 0x80;
|
res[1] = 0x80;
|
||||||
res[2] = 0x00;
|
res[2] = 0x00;
|
||||||
break;
|
break;
|
||||||
case JOYBUS_16KB_EEPROM:
|
case JOYBUS_16KB_EEPROM:
|
||||||
res[0] = 0x00;
|
res[0] = 0x00;
|
||||||
res[1] = 0xC0;
|
res[1] = 0xC0;
|
||||||
res[2] = 0x00;
|
res[2] = 0x00;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ircolib::panic("Device ID on unknown channel {}", channel);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
panic("Device ID on unknown channel {}", channel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PIF::ReadButtons(u8 *res) {
|
bool PIF::ReadButtons(u8 *res) {
|
||||||
if (channel >= 6) {
|
if (channel >= 6) {
|
||||||
res[0] = 0;
|
res[0] = 0;
|
||||||
res[1] = 0;
|
res[1] = 0;
|
||||||
res[2] = 0;
|
res[2] = 0;
|
||||||
res[3] = 0;
|
res[3] = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
switch (joybusDevices[channel].type) {
|
|
||||||
case JOYBUS_NONE:
|
|
||||||
res[0] = 0x00;
|
|
||||||
res[1] = 0x00;
|
|
||||||
res[2] = 0x00;
|
|
||||||
res[3] = 0x00;
|
|
||||||
return false; // Device not present
|
|
||||||
case JOYBUS_4KB_EEPROM:
|
|
||||||
case JOYBUS_16KB_EEPROM:
|
|
||||||
case JOYBUS_CONTROLLER:
|
|
||||||
if (movie.IsLoaded()) {
|
|
||||||
const Controller controller = movie.NextInputs();
|
|
||||||
res[0] = controller.byte1;
|
|
||||||
res[1] = controller.byte2;
|
|
||||||
res[2] = controller.joyX;
|
|
||||||
res[3] = controller.joyY;
|
|
||||||
} else {
|
|
||||||
res[0] = joybusDevices[channel].controller.byte1;
|
|
||||||
res[1] = joybusDevices[channel].controller.byte2;
|
|
||||||
res[2] = joybusDevices[channel].controller.joyX;
|
|
||||||
res[3] = joybusDevices[channel].controller.joyY;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
case JOYBUS_DANCEPAD:
|
|
||||||
case JOYBUS_VRU:
|
|
||||||
case JOYBUS_MOUSE:
|
|
||||||
case JOYBUS_RANDNET_KEYBOARD:
|
|
||||||
case JOYBUS_DENSHA_DE_GO:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
switch (joybusDevices[channel].type) {
|
||||||
|
case JOYBUS_NONE:
|
||||||
|
res[0] = 0x00;
|
||||||
|
res[1] = 0x00;
|
||||||
|
res[2] = 0x00;
|
||||||
|
res[3] = 0x00;
|
||||||
|
return false; // Device not present
|
||||||
|
case JOYBUS_4KB_EEPROM:
|
||||||
|
case JOYBUS_16KB_EEPROM:
|
||||||
|
case JOYBUS_CONTROLLER:
|
||||||
|
if (movie.IsLoaded()) {
|
||||||
|
const Controller controller = movie.NextInputs();
|
||||||
|
res[0] = controller.byte1;
|
||||||
|
res[1] = controller.byte2;
|
||||||
|
res[2] = controller.joyX;
|
||||||
|
res[3] = controller.joyY;
|
||||||
|
} else {
|
||||||
|
res[0] = joybusDevices[channel].controller.byte1;
|
||||||
|
res[1] = joybusDevices[channel].controller.byte2;
|
||||||
|
res[2] = joybusDevices[channel].controller.joyX;
|
||||||
|
res[3] = joybusDevices[channel].controller.joyY;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case JOYBUS_DANCEPAD:
|
||||||
|
case JOYBUS_VRU:
|
||||||
|
case JOYBUS_MOUSE:
|
||||||
|
case JOYBUS_RANDNET_KEYBOARD:
|
||||||
|
case JOYBUS_DENSHA_DE_GO:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -3,136 +3,133 @@
|
|||||||
#include <File.hpp>
|
#include <File.hpp>
|
||||||
#include <PIF.hpp>
|
#include <PIF.hpp>
|
||||||
|
|
||||||
|
|
||||||
union TASMovieControllerData {
|
union TASMovieControllerData {
|
||||||
struct {
|
struct {
|
||||||
unsigned dpadRight : 1;
|
unsigned dpadRight : 1;
|
||||||
unsigned dpadLeft : 1;
|
unsigned dpadLeft : 1;
|
||||||
unsigned dpadDown : 1;
|
unsigned dpadDown : 1;
|
||||||
unsigned dpadUp : 1;
|
unsigned dpadUp : 1;
|
||||||
unsigned start : 1;
|
unsigned start : 1;
|
||||||
unsigned z : 1;
|
unsigned z : 1;
|
||||||
unsigned b : 1;
|
unsigned b : 1;
|
||||||
unsigned a : 1;
|
unsigned a : 1;
|
||||||
unsigned cRight : 1;
|
unsigned cRight : 1;
|
||||||
unsigned cLeft : 1;
|
unsigned cLeft : 1;
|
||||||
unsigned cDown : 1;
|
unsigned cDown : 1;
|
||||||
unsigned cUp : 1;
|
unsigned cUp : 1;
|
||||||
unsigned r : 1;
|
unsigned r : 1;
|
||||||
unsigned l : 1;
|
unsigned l : 1;
|
||||||
unsigned : 2;
|
unsigned : 2;
|
||||||
signed analogX : 8;
|
signed analogX : 8;
|
||||||
signed analogY : 8;
|
signed analogY : 8;
|
||||||
};
|
};
|
||||||
u32 raw;
|
u32 raw;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
static_assert(sizeof(TASMovieControllerData) == 4);
|
static_assert(sizeof(TASMovieControllerData) == 4);
|
||||||
|
|
||||||
void MupenMovie::Load(const fs::path &path) {
|
void MupenMovie::Load(const fs::path &path) {
|
||||||
filename = path.stem().string();
|
filename = path.stem().string();
|
||||||
loadedTasMovie = ircolib::ReadFileBinary(path.string());
|
loadedTasMovie = ircolib::read_file_binary(path.string());
|
||||||
if (!IsLoaded()) {
|
if (!IsLoaded()) {
|
||||||
error("Error loading movie!");
|
ircolib::error("Error loading movie!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(&loadedTasMovieHeader, loadedTasMovie.data(), sizeof(TASMovieHeader));
|
std::memcpy(&loadedTasMovieHeader, loadedTasMovie.data(), sizeof(TASMovieHeader));
|
||||||
|
|
||||||
if (loadedTasMovieHeader.signature[0] != 0x4D || loadedTasMovieHeader.signature[1] != 0x36 ||
|
if (loadedTasMovieHeader.signature[0] != 0x4D || loadedTasMovieHeader.signature[1] != 0x36 ||
|
||||||
loadedTasMovieHeader.signature[2] != 0x34 || loadedTasMovieHeader.signature[3] != 0x1A) {
|
loadedTasMovieHeader.signature[2] != 0x34 || loadedTasMovieHeader.signature[3] != 0x1A) {
|
||||||
error("Failed to load movie: incorrect signature. Are you sure this is a valid movie?");
|
ircolib::error("Failed to load movie: incorrect signature. Are you sure this is a valid movie?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadedTasMovieHeader.version != 3) {
|
if (loadedTasMovieHeader.version != 3) {
|
||||||
error("This movie is version {}: only version 3 is supported.", loadedTasMovieHeader.version);
|
ircolib::error("This movie is version {}: only version 3 is supported.", loadedTasMovieHeader.version);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadedTasMovieHeader.startType != 2) {
|
if (loadedTasMovieHeader.startType != 2) {
|
||||||
error("Movie start type is {} - only movies with a start type of 2 are supported (start at power on)",
|
ircolib::error("Movie start type is {} - only movies with a start type of 2 are supported (start at power on)",
|
||||||
loadedTasMovieHeader.startType);
|
loadedTasMovieHeader.startType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info("Loaded movie '{}' ", loadedTasMovieHeader.movie_description);
|
ircolib::info("Loaded movie '{}' ", loadedTasMovieHeader.movie_description);
|
||||||
info("by {}", loadedTasMovieHeader.author_name);
|
ircolib::info("by {}", loadedTasMovieHeader.author_name);
|
||||||
info("{} controller(s) connected", loadedTasMovieHeader.numControllers);
|
ircolib::info("{} controller(s) connected", loadedTasMovieHeader.numControllers);
|
||||||
|
|
||||||
if (loadedTasMovieHeader.numControllers != 1) {
|
if (loadedTasMovieHeader.numControllers != 1) {
|
||||||
error("Currently, only movies with 1 controller connected are supported.");
|
ircolib::error("Currently, only movies with 1 controller connected are supported.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadedTasMovieIndex = sizeof(TASMovieHeader) - 4; // skip header
|
loadedTasMovieIndex = sizeof(TASMovieHeader) - 4; // skip header
|
||||||
}
|
}
|
||||||
|
|
||||||
MupenMovie::MupenMovie(const fs::path &path) {
|
MupenMovie::MupenMovie(const fs::path &path) { Load(path); }
|
||||||
Load(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MupenMovie::Reset() {
|
void MupenMovie::Reset() {
|
||||||
if (!IsLoaded())
|
if (!IsLoaded())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loadedTasMovieIndex = sizeof(TASMovieHeader) - 4; // skip header
|
loadedTasMovieIndex = sizeof(TASMovieHeader) - 4; // skip header
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void LogController(const n64::Controller &controller) {
|
FORCE_INLINE void LogController(const n64::Controller &controller) {
|
||||||
debug("c_right: {}", controller.cRight);
|
ircolib::debug("c_right: {}", controller.cRight);
|
||||||
debug("c_left: {}", controller.cLeft);
|
ircolib::debug("c_left: {}", controller.cLeft);
|
||||||
debug("c_down: {}", controller.cDown);
|
ircolib::debug("c_down: {}", controller.cDown);
|
||||||
debug("c_up: {}", controller.cUp);
|
ircolib::debug("c_up: {}", controller.cUp);
|
||||||
debug("r: {}", controller.r);
|
ircolib::debug("r: {}", controller.r);
|
||||||
debug("l: {}", controller.l);
|
ircolib::debug("l: {}", controller.l);
|
||||||
debug("dp_right: {}", controller.dpRight);
|
ircolib::debug("dp_right: {}", controller.dpRight);
|
||||||
debug("dp_left: {}", controller.dpLeft);
|
ircolib::debug("dp_left: {}", controller.dpLeft);
|
||||||
debug("dp_down: {}", controller.dpDown);
|
ircolib::debug("dp_down: {}", controller.dpDown);
|
||||||
debug("dp_up: {}", controller.dpUp);
|
ircolib::debug("dp_up: {}", controller.dpUp);
|
||||||
debug("z: {}", controller.z);
|
ircolib::debug("z: {}", controller.z);
|
||||||
debug("b: {}", controller.b);
|
ircolib::debug("b: {}", controller.b);
|
||||||
debug("a: {}", controller.a);
|
ircolib::debug("a: {}", controller.a);
|
||||||
debug("start: {}", controller.start);
|
ircolib::debug("start: {}", controller.start);
|
||||||
debug("joy_x: {}", controller.joyX);
|
ircolib::debug("joy_x: {}", controller.joyX);
|
||||||
debug("joy_y: {}", controller.joyY);
|
ircolib::debug("joy_y: {}", controller.joyY);
|
||||||
}
|
}
|
||||||
|
|
||||||
n64::Controller MupenMovie::NextInputs() {
|
n64::Controller MupenMovie::NextInputs() {
|
||||||
if (loadedTasMovieIndex + sizeof(TASMovieControllerData) > loadedTasMovie.size()) {
|
if (loadedTasMovieIndex + sizeof(TASMovieControllerData) > loadedTasMovie.size()) {
|
||||||
loadedTasMovie.clear();
|
loadedTasMovie.clear();
|
||||||
n64::Controller emptyController{};
|
n64::Controller emptyController{};
|
||||||
return emptyController;
|
return emptyController;
|
||||||
}
|
}
|
||||||
|
|
||||||
TASMovieControllerData movieCData{};
|
TASMovieControllerData movieCData{};
|
||||||
memcpy(&movieCData, &loadedTasMovie[loadedTasMovieIndex], sizeof(TASMovieControllerData));
|
memcpy(&movieCData, &loadedTasMovie[loadedTasMovieIndex], sizeof(TASMovieControllerData));
|
||||||
|
|
||||||
loadedTasMovieIndex += sizeof(TASMovieControllerData);
|
loadedTasMovieIndex += sizeof(TASMovieControllerData);
|
||||||
|
|
||||||
n64::Controller controller{};
|
n64::Controller controller{};
|
||||||
|
|
||||||
controller.cRight = movieCData.cRight;
|
controller.cRight = movieCData.cRight;
|
||||||
controller.cLeft = movieCData.cLeft;
|
controller.cLeft = movieCData.cLeft;
|
||||||
controller.cDown = movieCData.cDown;
|
controller.cDown = movieCData.cDown;
|
||||||
controller.cUp = movieCData.cUp;
|
controller.cUp = movieCData.cUp;
|
||||||
controller.r = movieCData.r;
|
controller.r = movieCData.r;
|
||||||
controller.l = movieCData.l;
|
controller.l = movieCData.l;
|
||||||
|
|
||||||
controller.dpRight = movieCData.dpadRight;
|
controller.dpRight = movieCData.dpadRight;
|
||||||
controller.dpLeft = movieCData.dpadLeft;
|
controller.dpLeft = movieCData.dpadLeft;
|
||||||
controller.dpDown = movieCData.dpadDown;
|
controller.dpDown = movieCData.dpadDown;
|
||||||
controller.dpUp = movieCData.dpadUp;
|
controller.dpUp = movieCData.dpadUp;
|
||||||
|
|
||||||
controller.z = movieCData.z;
|
controller.z = movieCData.z;
|
||||||
controller.b = movieCData.b;
|
controller.b = movieCData.b;
|
||||||
controller.a = movieCData.a;
|
controller.a = movieCData.a;
|
||||||
controller.start = movieCData.start;
|
controller.start = movieCData.start;
|
||||||
|
|
||||||
controller.joyX = movieCData.analogX;
|
controller.joyX = movieCData.analogX;
|
||||||
controller.joyY = movieCData.analogY;
|
controller.joyY = movieCData.analogY;
|
||||||
|
|
||||||
LogController(controller);
|
LogController(controller);
|
||||||
|
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
#include <core/mmio/RI.hpp>
|
#include <core/mmio/RI.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
RI::RI() { Reset(); }
|
RI::RI() { Reset(); }
|
||||||
|
|
||||||
void RI::Reset() {
|
void RI::Reset() {
|
||||||
mode = 0xE;
|
mode = 0xE;
|
||||||
config = 0x40;
|
config = 0x40;
|
||||||
select = 0x14;
|
select = 0x14;
|
||||||
refresh = 0x63634;
|
refresh = 0x63634;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto RI::Read(u32 addr) const -> u32 {
|
auto RI::Read(u32 addr) const -> u32 {
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0x04700000:
|
case 0x04700000:
|
||||||
return mode;
|
return mode;
|
||||||
case 0x04700004:
|
case 0x04700004:
|
||||||
return config;
|
return config;
|
||||||
case 0x0470000C:
|
case 0x0470000C:
|
||||||
return select;
|
return select;
|
||||||
case 0x04700010:
|
case 0x04700010:
|
||||||
return refresh;
|
return refresh;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled RI[{:08X}] read", addr);
|
ircolib::panic("Unhandled RI[{:08X}] read", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RI::Write(u32 addr, u32 val) {
|
void RI::Write(u32 addr, u32 val) {
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0x04700000:
|
case 0x04700000:
|
||||||
mode = val;
|
mode = val;
|
||||||
break;
|
break;
|
||||||
case 0x04700004:
|
case 0x04700004:
|
||||||
config = val;
|
config = val;
|
||||||
break;
|
break;
|
||||||
case 0x0470000C:
|
case 0x0470000C:
|
||||||
select = val;
|
select = val;
|
||||||
break;
|
break;
|
||||||
case 0x04700010:
|
case 0x04700010:
|
||||||
refresh = val;
|
refresh = val;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled RI[{:08X}] write with val {:08X}", addr, val);
|
ircolib::panic("Unhandled RI[{:08X}] write with val {:08X}", addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ auto SI::Read(u32 addr) const -> u32 {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Unhandled SI[{:08X}] read", addr);
|
ircolib::panic("Unhandled SI[{:08X}] read", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ void SI::DMA<true>() {
|
|||||||
for (int i = 0; i < 64; i++) {
|
for (int i = 0; i < 64; i++) {
|
||||||
mem.mmio.rdp.WriteRDRAM<u8>(dramAddr + i, pif.Read(pifAddr + i));
|
mem.mmio.rdp.WriteRDRAM<u8>(dramAddr + i, pif.Read(pifAddr + i));
|
||||||
}
|
}
|
||||||
trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr);
|
ircolib::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rdram -> pif
|
// rdram -> pif
|
||||||
@@ -54,7 +54,7 @@ void SI::DMA<false>() {
|
|||||||
for (int i = 0; i < 64; i++) {
|
for (int i = 0; i < 64; i++) {
|
||||||
pif.Write(pifAddr + i, mem.mmio.rdp.ReadRDRAM<u8>(dramAddr + i));
|
pif.Write(pifAddr + i, mem.mmio.rdp.ReadRDRAM<u8>(dramAddr + i));
|
||||||
}
|
}
|
||||||
trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr);
|
ircolib::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SI::DMA() {
|
void SI::DMA() {
|
||||||
@@ -89,7 +89,7 @@ void SI::Write(u32 addr, u32 val) {
|
|||||||
mem.mmio.mi.InterruptLower(MI::Interrupt::SI);
|
mem.mmio.mi.InterruptLower(MI::Interrupt::SI);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled SI[{:08X}] write ({:08X})", addr, val);
|
ircolib::panic("Unhandled SI[{:08X}] write ({:08X})", addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
VI::VI() { Reset(); }
|
VI::VI() { Reset(); }
|
||||||
@@ -55,7 +55,7 @@ u32 VI::Read(const u32 paddr) const {
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
panic("32-bit read access on unhandled VI register @ pc 0x{:016X}", u64(regs.oldPC));
|
ircolib::panic("32-bit read access on unhandled VI register @ pc 0x{:016X}", u64(regs.oldPC));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ void VI::Write(const u32 paddr, const u32 val) {
|
|||||||
case 0x0440003C:
|
case 0x0440003C:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented VI[{:08X}] write ({:08X})", paddr, val);
|
ircolib::panic("Unimplemented VI[{:08X}] write ({:08X})", paddr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Cop0::Cop0() { Reset(); }
|
Cop0::Cop0() { Reset(); }
|
||||||
@@ -103,7 +103,7 @@ u32 Cop0::GetReg32(const u8 addr) {
|
|||||||
case 31:
|
case 31:
|
||||||
return openbus;
|
return openbus;
|
||||||
default:
|
default:
|
||||||
panic("Unsupported word read from COP0 register {}", addr);
|
ircolib::panic("Unsupported word read from COP0 register {}", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ u64 Cop0::GetReg64(const u8 addr) const {
|
|||||||
case 31:
|
case 31:
|
||||||
return openbus;
|
return openbus;
|
||||||
default:
|
default:
|
||||||
panic("Unsupported dword read from COP0 register {}", addr);
|
ircolib::panic("Unsupported dword read from COP0 register {}", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ void Cop0::SetReg32(const u8 addr, const u32 value) {
|
|||||||
case 31:
|
case 31:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unsupported word write from COP0 register {}", addr);
|
ircolib::panic("Unsupported word write from COP0 register {}", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ void Cop0::SetReg64(const u8 addr, const u64 value) {
|
|||||||
ErrorEPC = (s64)value;
|
ErrorEPC = (s64)value;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unsupported dword write to COP0 register {}", addr);
|
ircolib::panic("Unsupported dword write to COP0 register {}", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +387,7 @@ void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status.bev) {
|
if (status.bev) {
|
||||||
panic("BEV bit set!");
|
ircolib::panic("BEV bit set!");
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.SetPC32(s32(0x80000000 + vectorOffset));
|
regs.SetPC32(s32(0x80000000 + vectorOffset));
|
||||||
@@ -408,7 +408,7 @@ void Cop0::HandleTLBException(const u64 vaddr) {
|
|||||||
Cop0::ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessType accessType) {
|
Cop0::ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessType accessType) {
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case NONE:
|
case NONE:
|
||||||
panic("Getting TLB exception with error NONE");
|
ircolib::panic("Getting TLB exception with error NONE");
|
||||||
case INVALID:
|
case INVALID:
|
||||||
case MISS:
|
case MISS:
|
||||||
return accessType == LOAD ? ExceptionCode::TLBLoad : ExceptionCode::TLBStore;
|
return accessType == LOAD ? ExceptionCode::TLBLoad : ExceptionCode::TLBStore;
|
||||||
@@ -417,7 +417,7 @@ Cop0::ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAcc
|
|||||||
case DISALLOWED_ADDRESS:
|
case DISALLOWED_ADDRESS:
|
||||||
return accessType == LOAD ? ExceptionCode::AddressErrorLoad : ExceptionCode::AddressErrorStore;
|
return accessType == LOAD ? ExceptionCode::AddressErrorLoad : ExceptionCode::AddressErrorStore;
|
||||||
default:
|
default:
|
||||||
panic("Getting TLB exception for unknown error code! ({})", static_cast<u8>(error));
|
ircolib::panic("Getting TLB exception for unknown error code! ({})", static_cast<u8>(error));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,14 +459,14 @@ void Cop0::decode(const Instruction instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented COP0 instruction {}", instr.cop_rs());
|
ircolib::panic("Unimplemented COP0 instruction {}", instr.cop_rs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
bool Cop0::MapVirtualAddress<u32, true>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
bool Cop0::MapVirtualAddress<u32, true>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
if (ircolib::IsInsideRange(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG))
|
if (ircolib::is_inside_range(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG))
|
||||||
return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
|
return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
|
||||||
|
|
||||||
tlbError = DISALLOWED_ADDRESS;
|
tlbError = DISALLOWED_ADDRESS;
|
||||||
@@ -476,25 +476,25 @@ bool Cop0::MapVirtualAddress<u32, true>(const TLBAccessType accessType, const u6
|
|||||||
template <>
|
template <>
|
||||||
bool Cop0::MapVirtualAddress<u32, false>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
bool Cop0::MapVirtualAddress<u32, false>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
u8 segment = static_cast<u32>(vaddr) >> 29 & 7;
|
u8 segment = static_cast<u32>(vaddr) >> 29 & 7;
|
||||||
if (ircolib::IsInsideRange(segment, 0, 3) || segment == 7)
|
if (ircolib::is_inside_range(segment, 0, 3) || segment == 7)
|
||||||
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
|
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(segment, 4, 5)) {
|
if (ircolib::is_inside_range(segment, 4, 5)) {
|
||||||
paddr = vaddr & 0x1FFFFFFF;
|
paddr = vaddr & 0x1FFFFFFF;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segment == 6)
|
if (segment == 6)
|
||||||
panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr);
|
ircolib::panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr);
|
||||||
|
|
||||||
panic("Should never end up in base case in MapVirtualAddress! ({:08X})", vaddr);
|
ircolib::panic("Should never end up in base case in MapVirtualAddress! ({:08X})", vaddr);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
bool Cop0::MapVirtualAddress<u64, true>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
bool Cop0::MapVirtualAddress<u64, true>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
if (ircolib::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF))
|
if (ircolib::is_inside_range(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF))
|
||||||
return ProbeTLB(accessType, vaddr, paddr);
|
return ProbeTLB(accessType, vaddr, paddr);
|
||||||
|
|
||||||
tlbError = DISALLOWED_ADDRESS;
|
tlbError = DISALLOWED_ADDRESS;
|
||||||
@@ -503,19 +503,19 @@ bool Cop0::MapVirtualAddress<u64, true>(const TLBAccessType accessType, const u6
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
if (ircolib::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) || // VREGION_XKUSEG
|
if (ircolib::is_inside_range(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) || // VREGION_XKUSEG
|
||||||
ircolib::IsInsideRange(vaddr, 0x4000000000000000, 0x400000FFFFFFFFFF) || // VREGION_XKSSEG
|
ircolib::is_inside_range(vaddr, 0x4000000000000000, 0x400000FFFFFFFFFF) || // VREGION_XKSSEG
|
||||||
ircolib::IsInsideRange(vaddr, 0xC000000000000000, 0xC00000FF7FFFFFFF) || // VREGION_XKSEG
|
ircolib::is_inside_range(vaddr, 0xC000000000000000, 0xC00000FF7FFFFFFF) || // VREGION_XKSEG
|
||||||
ircolib::IsInsideRange(vaddr, 0xFFFFFFFFE0000000, 0xFFFFFFFFFFFFFFFF)) // VREGION_CKSEG3
|
ircolib::is_inside_range(vaddr, 0xFFFFFFFFE0000000, 0xFFFFFFFFFFFFFFFF)) // VREGION_CKSEG3
|
||||||
return ProbeTLB(accessType, vaddr, paddr);
|
return ProbeTLB(accessType, vaddr, paddr);
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(vaddr, 0x8000000000000000, 0xBFFFFFFFFFFFFFFF)) { // VREGION_XKPHYS
|
if (ircolib::is_inside_range(vaddr, 0x8000000000000000, 0xBFFFFFFFFFFFFFFF)) { // VREGION_XKPHYS
|
||||||
if (!kernelMode)
|
if (!kernelMode)
|
||||||
panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
|
ircolib::panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
|
||||||
|
|
||||||
const u8 high_two_bits = (vaddr >> 62) & 0b11;
|
const u8 high_two_bits = (vaddr >> 62) & 0b11;
|
||||||
if (high_two_bits != 0b10)
|
if (high_two_bits != 0b10)
|
||||||
panic("Access to XKPHYS address 0x{:016X} with high two bits != 0b10!", vaddr);
|
ircolib::panic("Access to XKPHYS address 0x{:016X} with high two bits != 0b10!", vaddr);
|
||||||
|
|
||||||
const u8 subsegment = (vaddr >> 59) & 0b11;
|
const u8 subsegment = (vaddr >> 59) & 0b11;
|
||||||
bool cached = subsegment != 2; // do something with this eventually
|
bool cached = subsegment != 2; // do something with this eventually
|
||||||
@@ -530,31 +530,31 @@ bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(vaddr, 0xFFFFFFFF80000000, 0xFFFFFFFF9FFFFFFF) || // VREGION_CKSEG0
|
if (ircolib::is_inside_range(vaddr, 0xFFFFFFFF80000000, 0xFFFFFFFF9FFFFFFF) || // VREGION_CKSEG0
|
||||||
ircolib::IsInsideRange(vaddr, 0xFFFFFFFFA0000000, 0xFFFFFFFFBFFFFFFF)) { // VREGION_CKSEG1
|
ircolib::is_inside_range(vaddr, 0xFFFFFFFFA0000000, 0xFFFFFFFFBFFFFFFF)) { // VREGION_CKSEG1
|
||||||
u32 cut = u32(vaddr) >> 28;
|
u32 cut = u32(vaddr) >> 28;
|
||||||
u32 num = cut == 0xA;
|
u32 num = cut == 0xA;
|
||||||
// Identical to ksegX in 32 bit mode.
|
// Identical to ksegX in 32 bit mode.
|
||||||
// Unmapped translation. Subtract the base address of the space to get the physical address.
|
// Unmapped translation. Subtract the base address of the space to get the physical address.
|
||||||
paddr = vaddr - (cut << 28); // Implies cutting off the high 32 bits
|
paddr = vaddr - (cut << 28); // Implies cutting off the high 32 bits
|
||||||
trace("CKSEG{}: Translated 0x{:016X} to 0x{:08X}", num, vaddr, paddr);
|
ircolib::trace("CKSEG{}: Translated 0x{:016X} to 0x{:08X}", num, vaddr, paddr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(vaddr, 0x0000010000000000, 0x3FFFFFFFFFFFFFFF) || // VREGION_XBAD1
|
if (ircolib::is_inside_range(vaddr, 0x0000010000000000, 0x3FFFFFFFFFFFFFFF) || // VREGION_XBAD1
|
||||||
ircolib::IsInsideRange(vaddr, 0x4000010000000000, 0x7FFFFFFFFFFFFFFF) || // VREGION_XBAD2
|
ircolib::is_inside_range(vaddr, 0x4000010000000000, 0x7FFFFFFFFFFFFFFF) || // VREGION_XBAD2
|
||||||
ircolib::IsInsideRange(vaddr, 0xC00000FF80000000, 0xFFFFFFFF7FFFFFFF)) { // VREGION_XBAD3
|
ircolib::is_inside_range(vaddr, 0xC00000FF80000000, 0xFFFFFFFF7FFFFFFF)) { // VREGION_XBAD3
|
||||||
tlbError = DISALLOWED_ADDRESS;
|
tlbError = DISALLOWED_ADDRESS;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("Resolving virtual address 0x{:016X} in 64 bit mode", vaddr);
|
ircolib::panic("Resolving virtual address 0x{:016X} in 64 bit mode", vaddr);
|
||||||
return false; // just to silence warning
|
return false; // just to silence warning
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
if (supervisorMode)
|
if (supervisorMode)
|
||||||
panic("Supervisor mode memory access");
|
ircolib::panic("Supervisor mode memory access");
|
||||||
|
|
||||||
if (is64BitAddressing) [[unlikely]] {
|
if (is64BitAddressing) [[unlikely]] {
|
||||||
if (kernelMode) [[likely]]
|
if (kernelMode) [[likely]]
|
||||||
@@ -562,7 +562,7 @@ bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr)
|
|||||||
if (userMode)
|
if (userMode)
|
||||||
return MapVirtualAddress<u64, true>(accessType, vaddr, paddr);
|
return MapVirtualAddress<u64, true>(accessType, vaddr, paddr);
|
||||||
|
|
||||||
panic("Unknown mode! This should never happen!");
|
ircolib::panic("Unknown mode! This should never happen!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kernelMode) [[likely]]
|
if (kernelMode) [[likely]]
|
||||||
@@ -570,6 +570,6 @@ bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr)
|
|||||||
if (userMode)
|
if (userMode)
|
||||||
return MapVirtualAddress<u32, true>(accessType, vaddr, paddr);
|
return MapVirtualAddress<u32, true>(accessType, vaddr, paddr);
|
||||||
|
|
||||||
panic("Unknown mode! This should never happen!");
|
ircolib::panic("Unknown mode! This should never happen!");
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <Instruction.hpp>
|
#include <Instruction.hpp>
|
||||||
|
|
||||||
|
|||||||
+269
-269
@@ -1,290 +1,290 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Cop1::Cop1() { Reset(); }
|
Cop1::Cop1() { Reset(); }
|
||||||
|
|
||||||
void Cop1::Reset() {
|
void Cop1::Reset() {
|
||||||
fcr0 = 0xa00;
|
fcr0 = 0xa00;
|
||||||
fcr31.write(0x01000800);
|
fcr31.write(0x01000800);
|
||||||
memset(fgr, 0, 32 * sizeof(FloatingPointReg));
|
memset(fgr, 0, 32 * sizeof(FloatingPointReg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::decode(const Instruction instr) {
|
void Cop1::decode(const Instruction instr) {
|
||||||
switch (instr.cop_rs()) {
|
switch (instr.cop_rs()) {
|
||||||
// 000r_rccc
|
// 000r_rccc
|
||||||
case 0x00:
|
|
||||||
mfc1(instr);
|
|
||||||
break;
|
|
||||||
case 0x01:
|
|
||||||
dmfc1(instr);
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
cfc1(instr);
|
|
||||||
break;
|
|
||||||
case 0x03:
|
|
||||||
unimplemented();
|
|
||||||
break;
|
|
||||||
case 0x04:
|
|
||||||
mtc1(instr);
|
|
||||||
break;
|
|
||||||
case 0x05:
|
|
||||||
dmtc1(instr);
|
|
||||||
break;
|
|
||||||
case 0x06:
|
|
||||||
ctc1(instr);
|
|
||||||
break;
|
|
||||||
case 0x07:
|
|
||||||
unimplemented();
|
|
||||||
break;
|
|
||||||
case 0x10: // s
|
|
||||||
switch (instr.cop_funct()) {
|
|
||||||
case 0x00:
|
case 0x00:
|
||||||
adds(instr);
|
mfc1(instr);
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
subs(instr);
|
dmfc1(instr);
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
muls(instr);
|
cfc1(instr);
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
divs(instr);
|
unimplemented();
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
sqrts(instr);
|
mtc1(instr);
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case 0x05:
|
||||||
abss(instr);
|
dmtc1(instr);
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
movs(instr);
|
ctc1(instr);
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 0x07:
|
||||||
negs(instr);
|
unimplemented();
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case 0x10: // s
|
||||||
roundls(instr);
|
switch (instr.cop_funct()) {
|
||||||
break;
|
case 0x00:
|
||||||
case 0x09:
|
adds(instr);
|
||||||
truncls(instr);
|
break;
|
||||||
break;
|
case 0x01:
|
||||||
case 0x0A:
|
subs(instr);
|
||||||
ceills(instr);
|
break;
|
||||||
break;
|
case 0x02:
|
||||||
case 0x0B:
|
muls(instr);
|
||||||
floorls(instr);
|
break;
|
||||||
break;
|
case 0x03:
|
||||||
case 0x0C:
|
divs(instr);
|
||||||
roundws(instr);
|
break;
|
||||||
break;
|
case 0x04:
|
||||||
case 0x0D:
|
sqrts(instr);
|
||||||
truncws(instr);
|
break;
|
||||||
break;
|
case 0x05:
|
||||||
case 0x0E:
|
abss(instr);
|
||||||
ceilws(instr);
|
break;
|
||||||
break;
|
case 0x06:
|
||||||
case 0x0F:
|
movs(instr);
|
||||||
floorws(instr);
|
break;
|
||||||
break;
|
case 0x07:
|
||||||
case 0x21:
|
negs(instr);
|
||||||
cvtds(instr);
|
break;
|
||||||
break;
|
case 0x08:
|
||||||
case 0x24:
|
roundls(instr);
|
||||||
cvtws(instr);
|
break;
|
||||||
break;
|
case 0x09:
|
||||||
case 0x25:
|
truncls(instr);
|
||||||
cvtls(instr);
|
break;
|
||||||
break;
|
case 0x0A:
|
||||||
case 0x30:
|
ceills(instr);
|
||||||
cf<float>(instr);
|
break;
|
||||||
break;
|
case 0x0B:
|
||||||
case 0x31:
|
floorls(instr);
|
||||||
cun<float>(instr);
|
break;
|
||||||
break;
|
case 0x0C:
|
||||||
case 0x32:
|
roundws(instr);
|
||||||
ceq<float>(instr);
|
break;
|
||||||
break;
|
case 0x0D:
|
||||||
case 0x33:
|
truncws(instr);
|
||||||
cueq<float>(instr);
|
break;
|
||||||
break;
|
case 0x0E:
|
||||||
case 0x34:
|
ceilws(instr);
|
||||||
colt<float>(instr);
|
break;
|
||||||
break;
|
case 0x0F:
|
||||||
case 0x35:
|
floorws(instr);
|
||||||
cult<float>(instr);
|
break;
|
||||||
break;
|
case 0x21:
|
||||||
case 0x36:
|
cvtds(instr);
|
||||||
cole<float>(instr);
|
break;
|
||||||
break;
|
case 0x24:
|
||||||
case 0x37:
|
cvtws(instr);
|
||||||
cule<float>(instr);
|
break;
|
||||||
break;
|
case 0x25:
|
||||||
case 0x38:
|
cvtls(instr);
|
||||||
csf<float>(instr);
|
break;
|
||||||
break;
|
case 0x30:
|
||||||
case 0x39:
|
cf<float>(instr);
|
||||||
cngle<float>(instr);
|
break;
|
||||||
break;
|
case 0x31:
|
||||||
case 0x3A:
|
cun<float>(instr);
|
||||||
cseq<float>(instr);
|
break;
|
||||||
break;
|
case 0x32:
|
||||||
case 0x3B:
|
ceq<float>(instr);
|
||||||
cngl<float>(instr);
|
break;
|
||||||
break;
|
case 0x33:
|
||||||
case 0x3C:
|
cueq<float>(instr);
|
||||||
clt<float>(instr);
|
break;
|
||||||
break;
|
case 0x34:
|
||||||
case 0x3D:
|
colt<float>(instr);
|
||||||
cnge<float>(instr);
|
break;
|
||||||
break;
|
case 0x35:
|
||||||
case 0x3E:
|
cult<float>(instr);
|
||||||
cle<float>(instr);
|
break;
|
||||||
break;
|
case 0x36:
|
||||||
case 0x3F:
|
cole<float>(instr);
|
||||||
cngt<float>(instr);
|
break;
|
||||||
break;
|
case 0x37:
|
||||||
|
cule<float>(instr);
|
||||||
|
break;
|
||||||
|
case 0x38:
|
||||||
|
csf<float>(instr);
|
||||||
|
break;
|
||||||
|
case 0x39:
|
||||||
|
cngle<float>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3A:
|
||||||
|
cseq<float>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3B:
|
||||||
|
cngl<float>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3C:
|
||||||
|
clt<float>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3D:
|
||||||
|
cnge<float>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3E:
|
||||||
|
cle<float>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3F:
|
||||||
|
cngt<float>(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimplemented();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x11: // d
|
||||||
|
switch (instr.cop_funct()) {
|
||||||
|
case 0x00:
|
||||||
|
addd(instr);
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
subd(instr);
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
muld(instr);
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
divd(instr);
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
sqrtd(instr);
|
||||||
|
break;
|
||||||
|
case 0x05:
|
||||||
|
absd(instr);
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
movd(instr);
|
||||||
|
break;
|
||||||
|
case 0x07:
|
||||||
|
negd(instr);
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
roundld(instr);
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
truncld(instr);
|
||||||
|
break;
|
||||||
|
case 0x0A:
|
||||||
|
ceilld(instr);
|
||||||
|
break;
|
||||||
|
case 0x0B:
|
||||||
|
floorld(instr);
|
||||||
|
break;
|
||||||
|
case 0x0C:
|
||||||
|
roundwd(instr);
|
||||||
|
break;
|
||||||
|
case 0x0D:
|
||||||
|
truncwd(instr);
|
||||||
|
break;
|
||||||
|
case 0x0E:
|
||||||
|
ceilwd(instr);
|
||||||
|
break;
|
||||||
|
case 0x0F:
|
||||||
|
floorwd(instr);
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
cvtsd(instr);
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
cvtwd(instr);
|
||||||
|
break;
|
||||||
|
case 0x25:
|
||||||
|
cvtld(instr);
|
||||||
|
break;
|
||||||
|
case 0x30:
|
||||||
|
cf<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
cun<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x32:
|
||||||
|
ceq<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x33:
|
||||||
|
cueq<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x34:
|
||||||
|
colt<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x35:
|
||||||
|
cult<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x36:
|
||||||
|
cole<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x37:
|
||||||
|
cule<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x38:
|
||||||
|
csf<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x39:
|
||||||
|
cngle<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3A:
|
||||||
|
cseq<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3B:
|
||||||
|
cngl<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3C:
|
||||||
|
clt<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3D:
|
||||||
|
cnge<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3E:
|
||||||
|
cle<double>(instr);
|
||||||
|
break;
|
||||||
|
case 0x3F:
|
||||||
|
cngt<double>(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimplemented();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x14: // w
|
||||||
|
switch (instr.cop_funct()) {
|
||||||
|
case 0x20:
|
||||||
|
cvtsw(instr);
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
cvtdw(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimplemented();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x15: // l
|
||||||
|
switch (instr.cop_funct()) {
|
||||||
|
case 0x20:
|
||||||
|
cvtsl(instr);
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
cvtdl(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimplemented();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
unimplemented();
|
ircolib::panic("Unimplemented COP1 instruction {}", instr.cop_rs());
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 0x11: // d
|
|
||||||
switch (instr.cop_funct()) {
|
|
||||||
case 0x00:
|
|
||||||
addd(instr);
|
|
||||||
break;
|
|
||||||
case 0x01:
|
|
||||||
subd(instr);
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
muld(instr);
|
|
||||||
break;
|
|
||||||
case 0x03:
|
|
||||||
divd(instr);
|
|
||||||
break;
|
|
||||||
case 0x04:
|
|
||||||
sqrtd(instr);
|
|
||||||
break;
|
|
||||||
case 0x05:
|
|
||||||
absd(instr);
|
|
||||||
break;
|
|
||||||
case 0x06:
|
|
||||||
movd(instr);
|
|
||||||
break;
|
|
||||||
case 0x07:
|
|
||||||
negd(instr);
|
|
||||||
break;
|
|
||||||
case 0x08:
|
|
||||||
roundld(instr);
|
|
||||||
break;
|
|
||||||
case 0x09:
|
|
||||||
truncld(instr);
|
|
||||||
break;
|
|
||||||
case 0x0A:
|
|
||||||
ceilld(instr);
|
|
||||||
break;
|
|
||||||
case 0x0B:
|
|
||||||
floorld(instr);
|
|
||||||
break;
|
|
||||||
case 0x0C:
|
|
||||||
roundwd(instr);
|
|
||||||
break;
|
|
||||||
case 0x0D:
|
|
||||||
truncwd(instr);
|
|
||||||
break;
|
|
||||||
case 0x0E:
|
|
||||||
ceilwd(instr);
|
|
||||||
break;
|
|
||||||
case 0x0F:
|
|
||||||
floorwd(instr);
|
|
||||||
break;
|
|
||||||
case 0x20:
|
|
||||||
cvtsd(instr);
|
|
||||||
break;
|
|
||||||
case 0x24:
|
|
||||||
cvtwd(instr);
|
|
||||||
break;
|
|
||||||
case 0x25:
|
|
||||||
cvtld(instr);
|
|
||||||
break;
|
|
||||||
case 0x30:
|
|
||||||
cf<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x31:
|
|
||||||
cun<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x32:
|
|
||||||
ceq<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x33:
|
|
||||||
cueq<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x34:
|
|
||||||
colt<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x35:
|
|
||||||
cult<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x36:
|
|
||||||
cole<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x37:
|
|
||||||
cule<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x38:
|
|
||||||
csf<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x39:
|
|
||||||
cngle<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x3A:
|
|
||||||
cseq<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x3B:
|
|
||||||
cngl<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x3C:
|
|
||||||
clt<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x3D:
|
|
||||||
cnge<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x3E:
|
|
||||||
cle<double>(instr);
|
|
||||||
break;
|
|
||||||
case 0x3F:
|
|
||||||
cngt<double>(instr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
unimplemented();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x14: // w
|
|
||||||
switch (instr.cop_funct()) {
|
|
||||||
case 0x20:
|
|
||||||
cvtsw(instr);
|
|
||||||
break;
|
|
||||||
case 0x21:
|
|
||||||
cvtdw(instr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
unimplemented();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x15: // l
|
|
||||||
switch (instr.cop_funct()) {
|
|
||||||
case 0x20:
|
|
||||||
cvtsl(instr);
|
|
||||||
break;
|
|
||||||
case 0x21:
|
|
||||||
cvtdl(instr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
unimplemented();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Unimplemented COP1 instruction {}", instr.cop_rs());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
+425
-425
@@ -1,456 +1,456 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void RSP::special(const Instruction instr) {
|
void RSP::special(const Instruction instr) {
|
||||||
MI& mi = Core::GetMem().mmio.mi;
|
MI &mi = Core::GetMem().mmio.mi;
|
||||||
switch (instr.cop_funct()) {
|
switch (instr.cop_funct()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
if (instr != 0) {
|
if (instr != 0) {
|
||||||
sll(instr);
|
sll(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
srl(instr);
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
sra(instr);
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
sllv(instr);
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
srlv(instr);
|
||||||
|
break;
|
||||||
|
case 0x07:
|
||||||
|
srav(instr);
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
jr(instr);
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
jalr(instr);
|
||||||
|
break;
|
||||||
|
case 0x0D:
|
||||||
|
spStatus.halt = true;
|
||||||
|
steps = 0;
|
||||||
|
spStatus.broke = true;
|
||||||
|
if (spStatus.interruptOnBreak) {
|
||||||
|
mi.InterruptRaise(MI::Interrupt::SP);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
case 0x21:
|
||||||
|
add(instr);
|
||||||
|
break;
|
||||||
|
case 0x22:
|
||||||
|
case 0x23:
|
||||||
|
sub(instr);
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
and_(instr);
|
||||||
|
break;
|
||||||
|
case 0x25:
|
||||||
|
or_(instr);
|
||||||
|
break;
|
||||||
|
case 0x26:
|
||||||
|
xor_(instr);
|
||||||
|
break;
|
||||||
|
case 0x27:
|
||||||
|
nor(instr);
|
||||||
|
break;
|
||||||
|
case 0x2A:
|
||||||
|
slt(instr);
|
||||||
|
break;
|
||||||
|
case 0x2B:
|
||||||
|
sltu(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ircolib::panic("Unhandled RSP special instruction ({:06b})", instr.cop_funct());
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
srl(instr);
|
|
||||||
break;
|
|
||||||
case 0x03:
|
|
||||||
sra(instr);
|
|
||||||
break;
|
|
||||||
case 0x04:
|
|
||||||
sllv(instr);
|
|
||||||
break;
|
|
||||||
case 0x06:
|
|
||||||
srlv(instr);
|
|
||||||
break;
|
|
||||||
case 0x07:
|
|
||||||
srav(instr);
|
|
||||||
break;
|
|
||||||
case 0x08:
|
|
||||||
jr(instr);
|
|
||||||
break;
|
|
||||||
case 0x09:
|
|
||||||
jalr(instr);
|
|
||||||
break;
|
|
||||||
case 0x0D:
|
|
||||||
spStatus.halt = true;
|
|
||||||
steps = 0;
|
|
||||||
spStatus.broke = true;
|
|
||||||
if (spStatus.interruptOnBreak) {
|
|
||||||
mi.InterruptRaise(MI::Interrupt::SP);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x20:
|
|
||||||
case 0x21:
|
|
||||||
add(instr);
|
|
||||||
break;
|
|
||||||
case 0x22:
|
|
||||||
case 0x23:
|
|
||||||
sub(instr);
|
|
||||||
break;
|
|
||||||
case 0x24:
|
|
||||||
and_(instr);
|
|
||||||
break;
|
|
||||||
case 0x25:
|
|
||||||
or_(instr);
|
|
||||||
break;
|
|
||||||
case 0x26:
|
|
||||||
xor_(instr);
|
|
||||||
break;
|
|
||||||
case 0x27:
|
|
||||||
nor(instr);
|
|
||||||
break;
|
|
||||||
case 0x2A:
|
|
||||||
slt(instr);
|
|
||||||
break;
|
|
||||||
case 0x2B:
|
|
||||||
sltu(instr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Unhandled RSP special instruction ({:06b})", instr.cop_funct());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::regimm(const Instruction instr) {
|
void RSP::regimm(const Instruction instr) {
|
||||||
switch (instr.cop_rt()) {
|
switch (instr.cop_rt()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
b(instr, gpr[instr.rs()] < 0);
|
b(instr, gpr[instr.rs()] < 0);
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
b(instr, gpr[instr.rs()] >= 0);
|
b(instr, gpr[instr.rs()] >= 0);
|
||||||
break;
|
break;
|
||||||
case 0x10:
|
case 0x10:
|
||||||
blink(instr, gpr[instr.rs()] < 0);
|
blink(instr, gpr[instr.rs()] < 0);
|
||||||
break;
|
break;
|
||||||
case 0x11:
|
case 0x11:
|
||||||
blink(instr, gpr[instr.rs()] >= 0);
|
blink(instr, gpr[instr.rs()] >= 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled RSP regimm instruction ({:05b})", instr.cop_rt());
|
ircolib::panic("Unhandled RSP regimm instruction ({:05b})", instr.cop_rt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::lwc2(const Instruction instr) {
|
void RSP::lwc2(const Instruction instr) {
|
||||||
switch (instr.rd()) {
|
switch (instr.rd()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
lbv(instr);
|
lbv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
lsv(instr);
|
lsv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
llv(instr);
|
llv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
ldv(instr);
|
ldv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
lqv(instr);
|
lqv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case 0x05:
|
||||||
lrv(instr);
|
lrv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
lpv(instr);
|
lpv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 0x07:
|
||||||
luv(instr);
|
luv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
lhv(instr);
|
lhv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x09:
|
case 0x09:
|
||||||
lfv(instr);
|
lfv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0A:
|
case 0x0A:
|
||||||
break;
|
break;
|
||||||
case 0x0B:
|
case 0x0B:
|
||||||
ltv(instr);
|
ltv(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled RSP LWC2 {:05b}", instr.rd());
|
ircolib::panic("Unhandled RSP LWC2 {:05b}", instr.rd());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::swc2(const Instruction instr) {
|
void RSP::swc2(const Instruction instr) {
|
||||||
switch (instr.rd()) {
|
switch (instr.rd()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
sbv(instr);
|
sbv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
ssv(instr);
|
ssv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
slv(instr);
|
slv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
sdv(instr);
|
sdv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
sqv(instr);
|
sqv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case 0x05:
|
||||||
srv(instr);
|
srv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
spv(instr);
|
spv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 0x07:
|
||||||
suv(instr);
|
suv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
shv(instr);
|
shv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x09:
|
case 0x09:
|
||||||
sfv(instr);
|
sfv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0A:
|
case 0x0A:
|
||||||
swv(instr);
|
swv(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0B:
|
case 0x0B:
|
||||||
stv(instr);
|
stv(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled RSP SWC2 {:05b}", instr.rd());
|
ircolib::panic("Unhandled RSP SWC2 {:05b}", instr.rd());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::cop2(const Instruction instr) {
|
void RSP::cop2(const Instruction instr) {
|
||||||
switch (instr.cop_funct()) {
|
switch (instr.cop_funct()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
if (instr >> 25 & 1) {
|
if (instr >> 25 & 1) {
|
||||||
vmulf(instr);
|
vmulf(instr);
|
||||||
} else {
|
} else {
|
||||||
switch (instr.cop_rs()) {
|
switch (instr.cop_rs()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
mfc2(instr);
|
mfc2(instr);
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
cfc2(instr);
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
mtc2(instr);
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
ctc2(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ircolib::panic("Unhandled RSP COP2 sub ({:05b})", instr.cop_rs());
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x01:
|
||||||
cfc2(instr);
|
vmulu(instr);
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x02:
|
||||||
mtc2(instr);
|
vrndp(instr);
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x03:
|
||||||
ctc2(instr);
|
vmulq(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
case 0x04:
|
||||||
panic("Unhandled RSP COP2 sub ({:05b})", instr.cop_rs());
|
vmudl(instr);
|
||||||
}
|
break;
|
||||||
|
case 0x05:
|
||||||
|
vmudm(instr);
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
vmudn(instr);
|
||||||
|
break;
|
||||||
|
case 0x07:
|
||||||
|
vmudh(instr);
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
vmacf(instr);
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
vmacu(instr);
|
||||||
|
break;
|
||||||
|
case 0x0A:
|
||||||
|
vrndn(instr);
|
||||||
|
break;
|
||||||
|
case 0x0B:
|
||||||
|
vmacq(instr);
|
||||||
|
break;
|
||||||
|
case 0x0C:
|
||||||
|
vmadl(instr);
|
||||||
|
break;
|
||||||
|
case 0x0D:
|
||||||
|
vmadm(instr);
|
||||||
|
break;
|
||||||
|
case 0x0E:
|
||||||
|
vmadn(instr);
|
||||||
|
break;
|
||||||
|
case 0x0F:
|
||||||
|
vmadh(instr);
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
vadd(instr);
|
||||||
|
break;
|
||||||
|
case 0x11:
|
||||||
|
vsub(instr);
|
||||||
|
break;
|
||||||
|
case 0x12:
|
||||||
|
vzero(instr);
|
||||||
|
break;
|
||||||
|
case 0x13:
|
||||||
|
vabs(instr);
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
vaddc(instr);
|
||||||
|
break;
|
||||||
|
case 0x15:
|
||||||
|
vsubc(instr);
|
||||||
|
break;
|
||||||
|
case 0x16 ... 0x1C:
|
||||||
|
case 0x1E:
|
||||||
|
case 0x1F:
|
||||||
|
case 0x2E:
|
||||||
|
case 0x2F:
|
||||||
|
vzero(instr);
|
||||||
|
break;
|
||||||
|
case 0x1D:
|
||||||
|
vsar(instr);
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
vlt(instr);
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
veq(instr);
|
||||||
|
break;
|
||||||
|
case 0x22:
|
||||||
|
vne(instr);
|
||||||
|
break;
|
||||||
|
case 0x23:
|
||||||
|
vge(instr);
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
vcl(instr);
|
||||||
|
break;
|
||||||
|
case 0x25:
|
||||||
|
vch(instr);
|
||||||
|
break;
|
||||||
|
case 0x26:
|
||||||
|
vcr(instr);
|
||||||
|
break;
|
||||||
|
case 0x27:
|
||||||
|
vmrg(instr);
|
||||||
|
break;
|
||||||
|
case 0x28:
|
||||||
|
vand(instr);
|
||||||
|
break;
|
||||||
|
case 0x29:
|
||||||
|
vnand(instr);
|
||||||
|
break;
|
||||||
|
case 0x2A:
|
||||||
|
vor(instr);
|
||||||
|
break;
|
||||||
|
case 0x2B:
|
||||||
|
vnor(instr);
|
||||||
|
break;
|
||||||
|
case 0x2C:
|
||||||
|
vxor(instr);
|
||||||
|
break;
|
||||||
|
case 0x2D:
|
||||||
|
vnxor(instr);
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
vrcpl(instr);
|
||||||
|
break;
|
||||||
|
case 0x35:
|
||||||
|
vrsql(instr);
|
||||||
|
break;
|
||||||
|
case 0x32:
|
||||||
|
case 0x36:
|
||||||
|
vrcph(instr);
|
||||||
|
break;
|
||||||
|
case 0x30:
|
||||||
|
vrcp(instr);
|
||||||
|
break;
|
||||||
|
case 0x33:
|
||||||
|
vmov(instr);
|
||||||
|
break;
|
||||||
|
case 0x34:
|
||||||
|
vrsq(instr);
|
||||||
|
break;
|
||||||
|
case 0x38 ... 0x3E:
|
||||||
|
vzero(instr);
|
||||||
|
break;
|
||||||
|
case 0x37:
|
||||||
|
case 0x3F:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ircolib::panic("Unhandled RSP COP2 ({:06b})", instr.cop_funct());
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 0x01:
|
|
||||||
vmulu(instr);
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
vrndp(instr);
|
|
||||||
break;
|
|
||||||
case 0x03:
|
|
||||||
vmulq(instr);
|
|
||||||
break;
|
|
||||||
case 0x04:
|
|
||||||
vmudl(instr);
|
|
||||||
break;
|
|
||||||
case 0x05:
|
|
||||||
vmudm(instr);
|
|
||||||
break;
|
|
||||||
case 0x06:
|
|
||||||
vmudn(instr);
|
|
||||||
break;
|
|
||||||
case 0x07:
|
|
||||||
vmudh(instr);
|
|
||||||
break;
|
|
||||||
case 0x08:
|
|
||||||
vmacf(instr);
|
|
||||||
break;
|
|
||||||
case 0x09:
|
|
||||||
vmacu(instr);
|
|
||||||
break;
|
|
||||||
case 0x0A:
|
|
||||||
vrndn(instr);
|
|
||||||
break;
|
|
||||||
case 0x0B:
|
|
||||||
vmacq(instr);
|
|
||||||
break;
|
|
||||||
case 0x0C:
|
|
||||||
vmadl(instr);
|
|
||||||
break;
|
|
||||||
case 0x0D:
|
|
||||||
vmadm(instr);
|
|
||||||
break;
|
|
||||||
case 0x0E:
|
|
||||||
vmadn(instr);
|
|
||||||
break;
|
|
||||||
case 0x0F:
|
|
||||||
vmadh(instr);
|
|
||||||
break;
|
|
||||||
case 0x10:
|
|
||||||
vadd(instr);
|
|
||||||
break;
|
|
||||||
case 0x11:
|
|
||||||
vsub(instr);
|
|
||||||
break;
|
|
||||||
case 0x12:
|
|
||||||
vzero(instr);
|
|
||||||
break;
|
|
||||||
case 0x13:
|
|
||||||
vabs(instr);
|
|
||||||
break;
|
|
||||||
case 0x14:
|
|
||||||
vaddc(instr);
|
|
||||||
break;
|
|
||||||
case 0x15:
|
|
||||||
vsubc(instr);
|
|
||||||
break;
|
|
||||||
case 0x16 ... 0x1C:
|
|
||||||
case 0x1E:
|
|
||||||
case 0x1F:
|
|
||||||
case 0x2E:
|
|
||||||
case 0x2F:
|
|
||||||
vzero(instr);
|
|
||||||
break;
|
|
||||||
case 0x1D:
|
|
||||||
vsar(instr);
|
|
||||||
break;
|
|
||||||
case 0x20:
|
|
||||||
vlt(instr);
|
|
||||||
break;
|
|
||||||
case 0x21:
|
|
||||||
veq(instr);
|
|
||||||
break;
|
|
||||||
case 0x22:
|
|
||||||
vne(instr);
|
|
||||||
break;
|
|
||||||
case 0x23:
|
|
||||||
vge(instr);
|
|
||||||
break;
|
|
||||||
case 0x24:
|
|
||||||
vcl(instr);
|
|
||||||
break;
|
|
||||||
case 0x25:
|
|
||||||
vch(instr);
|
|
||||||
break;
|
|
||||||
case 0x26:
|
|
||||||
vcr(instr);
|
|
||||||
break;
|
|
||||||
case 0x27:
|
|
||||||
vmrg(instr);
|
|
||||||
break;
|
|
||||||
case 0x28:
|
|
||||||
vand(instr);
|
|
||||||
break;
|
|
||||||
case 0x29:
|
|
||||||
vnand(instr);
|
|
||||||
break;
|
|
||||||
case 0x2A:
|
|
||||||
vor(instr);
|
|
||||||
break;
|
|
||||||
case 0x2B:
|
|
||||||
vnor(instr);
|
|
||||||
break;
|
|
||||||
case 0x2C:
|
|
||||||
vxor(instr);
|
|
||||||
break;
|
|
||||||
case 0x2D:
|
|
||||||
vnxor(instr);
|
|
||||||
break;
|
|
||||||
case 0x31:
|
|
||||||
vrcpl(instr);
|
|
||||||
break;
|
|
||||||
case 0x35:
|
|
||||||
vrsql(instr);
|
|
||||||
break;
|
|
||||||
case 0x32:
|
|
||||||
case 0x36:
|
|
||||||
vrcph(instr);
|
|
||||||
break;
|
|
||||||
case 0x30:
|
|
||||||
vrcp(instr);
|
|
||||||
break;
|
|
||||||
case 0x33:
|
|
||||||
vmov(instr);
|
|
||||||
break;
|
|
||||||
case 0x34:
|
|
||||||
vrsq(instr);
|
|
||||||
break;
|
|
||||||
case 0x38 ... 0x3E:
|
|
||||||
vzero(instr);
|
|
||||||
break;
|
|
||||||
case 0x37:
|
|
||||||
case 0x3F:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Unhandled RSP COP2 ({:06b})", instr.cop_funct());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::cop0(const Instruction instr) {
|
void RSP::cop0(const Instruction instr) {
|
||||||
if ((instr & 0x7FF) == 0) {
|
if ((instr & 0x7FF) == 0) {
|
||||||
switch (instr.cop_rs()) {
|
switch (instr.cop_rs()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
mfc0(Core::GetMem().mmio.rdp, instr);
|
mfc0(Core::GetMem().mmio.rdp, instr);
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
mtc0(instr);
|
mtc0(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled RSP COP0 ({:05b})", instr.cop_rs());
|
ircolib::panic("Unhandled RSP COP0 ({:05b})", instr.cop_rs());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ircolib::panic("RSP COP0 unknown {:08X}", u32(instr));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
panic("RSP COP0 unknown {:08X}", u32(instr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::Exec(const Instruction instr) {
|
void RSP::Exec(const Instruction instr) {
|
||||||
Mem& mem = Core::GetMem();
|
Mem &mem = Core::GetMem();
|
||||||
MMIO &mmio = mem.mmio;
|
MMIO &mmio = mem.mmio;
|
||||||
MI &mi = mmio.mi;
|
MI &mi = mmio.mi;
|
||||||
switch (instr.opcode()) {
|
switch (instr.opcode()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
special(instr);
|
special(instr);
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
regimm(instr);
|
regimm(instr);
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
j(instr);
|
j(instr);
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
jal(instr);
|
jal(instr);
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
b(instr, gpr[instr.rt()] == gpr[instr.rs()]);
|
b(instr, gpr[instr.rt()] == gpr[instr.rs()]);
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case 0x05:
|
||||||
b(instr, gpr[instr.rt()] != gpr[instr.rs()]);
|
b(instr, gpr[instr.rt()] != gpr[instr.rs()]);
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
b(instr, gpr[instr.rs()] <= 0);
|
b(instr, gpr[instr.rs()] <= 0);
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 0x07:
|
||||||
b(instr, gpr[instr.rs()] > 0);
|
b(instr, gpr[instr.rs()] > 0);
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
case 0x09:
|
case 0x09:
|
||||||
addi(instr);
|
addi(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0A:
|
case 0x0A:
|
||||||
slti(instr);
|
slti(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0B:
|
case 0x0B:
|
||||||
sltiu(instr);
|
sltiu(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0C:
|
case 0x0C:
|
||||||
andi(instr);
|
andi(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0D:
|
case 0x0D:
|
||||||
ori(instr);
|
ori(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0E:
|
case 0x0E:
|
||||||
xori(instr);
|
xori(instr);
|
||||||
break;
|
break;
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
lui(instr);
|
lui(instr);
|
||||||
break;
|
break;
|
||||||
case 0x10:
|
case 0x10:
|
||||||
cop0(instr);
|
cop0(instr);
|
||||||
break;
|
break;
|
||||||
case 0x12:
|
case 0x12:
|
||||||
cop2(instr);
|
cop2(instr);
|
||||||
break;
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
lb(instr);
|
lb(instr);
|
||||||
break;
|
break;
|
||||||
case 0x21:
|
case 0x21:
|
||||||
lh(instr);
|
lh(instr);
|
||||||
break;
|
break;
|
||||||
case 0x23:
|
case 0x23:
|
||||||
case 0x27:
|
case 0x27:
|
||||||
lw(instr);
|
lw(instr);
|
||||||
break;
|
break;
|
||||||
case 0x24:
|
case 0x24:
|
||||||
lbu(instr);
|
lbu(instr);
|
||||||
break;
|
break;
|
||||||
case 0x25:
|
case 0x25:
|
||||||
lhu(instr);
|
lhu(instr);
|
||||||
break;
|
break;
|
||||||
case 0x28:
|
case 0x28:
|
||||||
sb(instr);
|
sb(instr);
|
||||||
break;
|
break;
|
||||||
case 0x29:
|
case 0x29:
|
||||||
sh(instr);
|
sh(instr);
|
||||||
break;
|
break;
|
||||||
case 0x2B:
|
case 0x2B:
|
||||||
sw(instr);
|
sw(instr);
|
||||||
break;
|
break;
|
||||||
case 0x32:
|
case 0x32:
|
||||||
lwc2(instr);
|
lwc2(instr);
|
||||||
break;
|
break;
|
||||||
case 0x3A:
|
case 0x3A:
|
||||||
swc2(instr);
|
swc2(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mem.DumpIMEM();
|
mem.DumpIMEM();
|
||||||
panic("Unhandled RSP instruction ({:06b}, {:04X})", instr.opcode(), oldPC);
|
ircolib::panic("Unhandled RSP instruction ({:06b}, {:04X})", instr.opcode(), oldPC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
+1254
-1254
File diff suppressed because it is too large
Load Diff
@@ -14,9 +14,9 @@ void EmuThread::run() {
|
|||||||
const auto index = e.gdevice.which;
|
const auto index = e.gdevice.which;
|
||||||
|
|
||||||
gamepad = SDL_OpenGamepad(index);
|
gamepad = SDL_OpenGamepad(index);
|
||||||
warn("Found controller!");
|
ircolib::warn("Found controller!");
|
||||||
warn("Name: {}", SDL_GetGamepadName(gamepad));
|
ircolib::warn("Name: {}", SDL_GetGamepadName(gamepad));
|
||||||
warn("Vendor: {}", SDL_GetGamepadVendor(gamepad));
|
ircolib::warn("Vendor: {}", SDL_GetGamepadVendor(gamepad));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,26 +36,8 @@ KaizenGui::KaizenGui() noexcept : QMainWindow(nullptr), settings(QSettings::User
|
|||||||
|
|
||||||
connect(romsListTable, &RomsListTable::cleared, this, [&] { centralWidget->setCurrentWidget(romPathNotSet); });
|
connect(romsListTable, &RomsListTable::cleared, this, [&] { centralWidget->setCurrentWidget(romPathNotSet); });
|
||||||
|
|
||||||
connect(romsListTable, &RomsListTable::populateFinished, this, [&] {
|
|
||||||
for (int i = 0; i < romsListTable->size(); i++) {
|
|
||||||
const auto &[countryCode, version, _, name, regions, lastPlayed, timePlayed] = (*romsListTable)[i];
|
|
||||||
|
|
||||||
romsListTable->insertRow(i);
|
|
||||||
romsListTable->setItem(
|
|
||||||
i, 0,
|
|
||||||
new QTableWidgetItem(
|
|
||||||
std::format("{} ({}) (Rev {})", name, n64::GameDB::regionCodeToReadable(countryCode), version)
|
|
||||||
.c_str()));
|
|
||||||
romsListTable->setItem(i, 1, new QTableWidgetItem(regions.c_str()));
|
|
||||||
romsListTable->setItem(i, 2, new QTableWidgetItem(lastPlayed.c_str()));
|
|
||||||
romsListTable->setItem(i, 3, new QTableWidgetItem(timePlayed.c_str()));
|
|
||||||
}
|
|
||||||
romsListTable->resizeRowsToContents();
|
|
||||||
centralWidget->setCurrentWidget(romsListTable);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(romsListTable, &QTableWidget::cellDoubleClicked, this,
|
connect(romsListTable, &QTableWidget::cellDoubleClicked, this,
|
||||||
[&](int row, int) { LoadROM((*romsListTable)[row].path); });
|
[&](int row, int) { LoadROM(romsListTable->GetPathForClickedCell(row)); });
|
||||||
|
|
||||||
installEventFilter(this);
|
installEventFilter(this);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ static CompositorCategory GetOSCompositorCategory() {
|
|||||||
if (platform_name == QStringLiteral("cocoa") || platform_name == QStringLiteral("ios"))
|
if (platform_name == QStringLiteral("cocoa") || platform_name == QStringLiteral("ios"))
|
||||||
return CompositorCategory::MacOS;
|
return CompositorCategory::MacOS;
|
||||||
|
|
||||||
warn("Unknown Qt platform!");
|
ircolib::warn("Unknown Qt platform!");
|
||||||
return CompositorCategory::Windows;
|
return CompositorCategory::Windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ RenderWidget::RenderWidget() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!Vulkan::Context::init_loader(nullptr)) {
|
if (!Vulkan::Context::init_loader(nullptr)) {
|
||||||
panic("Could not initialize Vulkan ICD");
|
ircolib::panic("Could not initialize Vulkan ICD");
|
||||||
}
|
}
|
||||||
|
|
||||||
qtVkInstanceFactory = std::make_unique<QtInstanceFactory>();
|
qtVkInstanceFactory = std::make_unique<QtInstanceFactory>();
|
||||||
|
|||||||
+18
-16
@@ -13,38 +13,31 @@ RomsListTable::RomsListTable(GeneralSettings *general) {
|
|||||||
setSelectionBehavior(QAbstractItemView::SelectRows);
|
setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
setSortingEnabled(true);
|
setSortingEnabled(true);
|
||||||
setColumnCount(4);
|
setColumnCount(5);
|
||||||
setHorizontalHeaderItem(0, new QTableWidgetItem("Name"));
|
setHorizontalHeaderItem(0, new QTableWidgetItem("Name"));
|
||||||
setHorizontalHeaderItem(1, new QTableWidgetItem("Regions"));
|
setHorizontalHeaderItem(1, new QTableWidgetItem("Regions"));
|
||||||
setHorizontalHeaderItem(2, new QTableWidgetItem("Last played"));
|
setHorizontalHeaderItem(2, new QTableWidgetItem("Last played"));
|
||||||
setHorizontalHeaderItem(3, new QTableWidgetItem("Time played"));
|
setHorizontalHeaderItem(3, new QTableWidgetItem("Time played"));
|
||||||
|
setHorizontalHeaderItem(4, new QTableWidgetItem("__path__"));
|
||||||
|
hideColumn(4);
|
||||||
|
|
||||||
connect(general, &GeneralSettings::romFolderSelected, this, [&] {
|
connect(general, &GeneralSettings::romFolderSelected, this, [&] {
|
||||||
std::thread popThread([&] {
|
std::thread popThread([&] { populate(Options::GetRomsPath()); });
|
||||||
populate(Options::GetRomsPath());
|
|
||||||
emit populateFinished();
|
|
||||||
});
|
|
||||||
|
|
||||||
popThread.detach();
|
popThread.detach();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(general, &GeneralSettings::romFolderCleared, this, [&] {
|
connect(general, &GeneralSettings::romFolderCleared, this, [&] {
|
||||||
for (int i = 0; i < rowCount(); i++)
|
clearContents();
|
||||||
removeRow(i);
|
|
||||||
romsList = {};
|
|
||||||
emit cleared();
|
emit cleared();
|
||||||
});
|
});
|
||||||
|
|
||||||
std::thread popThread([&] {
|
std::thread popThread([&] { populate(Options::GetRomsPath()); });
|
||||||
populate(Options::GetRomsPath());
|
|
||||||
emit populateFinished();
|
|
||||||
});
|
|
||||||
|
|
||||||
popThread.detach();
|
popThread.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomsListTable::populate(const std::string &romsPath) {
|
void RomsListTable::populate(const std::string &romsPath) {
|
||||||
if (!romsPath.empty()) {
|
if (!romsPath.empty()) {
|
||||||
|
int i = 0;
|
||||||
for (const auto &file : fs::recursive_directory_iterator{romsPath}) {
|
for (const auto &file : fs::recursive_directory_iterator{romsPath}) {
|
||||||
if (!file.is_regular_file())
|
if (!file.is_regular_file())
|
||||||
continue;
|
continue;
|
||||||
@@ -67,8 +60,17 @@ void RomsListTable::populate(const std::string &romsPath) {
|
|||||||
if (rom.gameNameDB.empty())
|
if (rom.gameNameDB.empty())
|
||||||
rom.gameNameDB = fs::path(filename).stem().string();
|
rom.gameNameDB = fs::path(filename).stem().string();
|
||||||
|
|
||||||
romsList.push_back(
|
insertRow(i);
|
||||||
{rom.header.countryCode, rom.header.version, filename, rom.gameNameDB, regions, "Never", "0h 00m 00s"});
|
setItem(i, 0,
|
||||||
|
new QTableWidgetItem(std::format("{} ({}) (Rev {})", rom.gameNameDB,
|
||||||
|
n64::GameDB::regionCodeToReadable(rom.header.countryCode),
|
||||||
|
rom.header.version)
|
||||||
|
.c_str()));
|
||||||
|
setItem(i, 1, new QTableWidgetItem(regions.c_str()));
|
||||||
|
setItem(i, 2, new QTableWidgetItem("Never"));
|
||||||
|
setItem(i, 3, new QTableWidgetItem("0h 0m 0s"));
|
||||||
|
setItem(i, 4, new QTableWidgetItem(filename.c_str()));
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ class RomsListTable : public QTableWidget {
|
|||||||
void populate(const std::string &);
|
void populate(const std::string &);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::vector<RomsListEntry> romsList;
|
|
||||||
RomsListTable(GeneralSettings *);
|
RomsListTable(GeneralSettings *);
|
||||||
|
|
||||||
size_t size() { return romsList.size(); }
|
size_t size() { return rowCount(); }
|
||||||
|
|
||||||
RomsListEntry &operator[](const size_t i) { return romsList[i]; }
|
std::string GetPathForClickedCell(int i) const { return item(i, 4)->text().toStdString(); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void populateFinished();
|
|
||||||
void cleared();
|
void cleared();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <CPUSettings.hpp>
|
#include <CPUSettings.hpp>
|
||||||
#include <Options.hpp>
|
#include <Options.hpp>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
CPUSettings::CPUSettings() : settings(QSettings::UserScope) {
|
CPUSettings::CPUSettings() : settings(QSettings::UserScope) {
|
||||||
types = new QComboBox();
|
types = new QComboBox();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <Options.hpp>
|
#include <Options.hpp>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
GeneralSettings::GeneralSettings() : settings(QSettings::UserScope) {
|
GeneralSettings::GeneralSettings() : settings(QSettings::UserScope) {
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <ircolib/types.hpp>
|
#include <ircolib/types.hpp>
|
||||||
#ifdef USE_NEON
|
|
||||||
#include <sse2neon.h>
|
|
||||||
#else
|
|
||||||
#include <emmintrin.h>
|
|
||||||
#include <smmintrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using u8 = ircolib::u8;
|
using u8 = ircolib::u8;
|
||||||
using u16 = ircolib::u16;
|
using u16 = ircolib::u16;
|
||||||
|
|||||||
+37
-36
@@ -4,55 +4,56 @@
|
|||||||
|
|
||||||
namespace Util {
|
namespace Util {
|
||||||
std::vector<u8> OpenROM(const std::string &filename, size_t &sizeAdjusted) {
|
std::vector<u8> OpenROM(const std::string &filename, size_t &sizeAdjusted) {
|
||||||
auto buf = ircolib::ReadFileBinary(filename);
|
auto buf = ircolib::read_file_binary(filename);
|
||||||
sizeAdjusted = ircolib::NextPow2(buf.size());
|
sizeAdjusted = ircolib::next_pow2(buf.size());
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> OpenArchive(const std::string &path, size_t &sizeAdjusted) {
|
std::vector<u8> OpenArchive(const std::string &path, size_t &sizeAdjusted) {
|
||||||
const auto stream = ar_open_file(fs::path(path).string().c_str());
|
const auto stream = ar_open_file(fs::path(path).string().c_str());
|
||||||
|
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
panic("Could not open archive! Are you sure it's an archive?");
|
ircolib::panic("Could not open archive! Are you sure it's an archive?");
|
||||||
}
|
}
|
||||||
|
|
||||||
ar_archive *archive = ar_open_zip_archive(stream, false);
|
ar_archive *archive = ar_open_zip_archive(stream, false);
|
||||||
|
|
||||||
if (!archive)
|
if (!archive)
|
||||||
archive = ar_open_rar_archive(stream);
|
archive = ar_open_rar_archive(stream);
|
||||||
if (!archive)
|
if (!archive)
|
||||||
archive = ar_open_7z_archive(stream);
|
archive = ar_open_7z_archive(stream);
|
||||||
if (!archive)
|
if (!archive)
|
||||||
archive = ar_open_tar_archive(stream);
|
archive = ar_open_tar_archive(stream);
|
||||||
|
|
||||||
if (!archive) {
|
if (!archive) {
|
||||||
ar_close(stream);
|
ar_close(stream);
|
||||||
panic("Could not open archive! Are you sure it's a supported archive? (7z, zip, rar and tar are supported)");
|
ircolib::panic(
|
||||||
}
|
"Could not open archive! Are you sure it's a supported archive? (7z, zip, rar and tar are supported)");
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<u8> buf{};
|
std::vector<u8> buf{};
|
||||||
|
|
||||||
std::vector<std::string> rom_exts{".n64", ".z64", ".v64", ".N64", ".Z64", ".V64"};
|
std::vector<std::string> rom_exts{".n64", ".z64", ".v64", ".N64", ".Z64", ".V64"};
|
||||||
|
|
||||||
while (ar_parse_entry(archive)) {
|
while (ar_parse_entry(archive)) {
|
||||||
auto filename = ar_entry_get_name(archive);
|
auto filename = ar_entry_get_name(archive);
|
||||||
auto extension = fs::path(filename).extension();
|
auto extension = fs::path(filename).extension();
|
||||||
|
|
||||||
if (std::ranges::any_of(rom_exts, [&](const auto &x) { return extension == x; })) {
|
if (std::ranges::any_of(rom_exts, [&](const auto &x) { return extension == x; })) {
|
||||||
const auto size = ar_entry_get_size(archive);
|
const auto size = ar_entry_get_size(archive);
|
||||||
sizeAdjusted = ircolib::NextPow2(size);
|
sizeAdjusted = ircolib::next_pow2(size);
|
||||||
buf.resize(sizeAdjusted);
|
buf.resize(sizeAdjusted);
|
||||||
ar_entry_uncompress(archive, buf.data(), size);
|
ar_entry_uncompress(archive, buf.data(), size);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar_close_archive(archive);
|
||||||
|
ar_close(stream);
|
||||||
|
ircolib::panic("Could not find any rom image in the archive!");
|
||||||
}
|
}
|
||||||
|
|
||||||
ar_close_archive(archive);
|
ar_close_archive(archive);
|
||||||
ar_close(stream);
|
ar_close(stream);
|
||||||
panic("Could not find any rom image in the archive!");
|
return buf;
|
||||||
}
|
|
||||||
|
|
||||||
ar_close_archive(archive);
|
|
||||||
ar_close(stream);
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
}
|
} // namespace Util
|
||||||
|
|||||||
+2
-1
@@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <log.hpp>
|
#include <ircolib/log.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <ircolib/file.hpp>
|
#include <ircolib/file.hpp>
|
||||||
|
#include <types.hpp>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <common.hpp>
|
|
||||||
#include <print>
|
|
||||||
#include <string>
|
|
||||||
#if !defined(NDEBUG) && !defined(_WIN32)
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Util {
|
|
||||||
enum LogLevel : u8 { Trace, Debug, Info, Warn, Error, Always };
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
static constexpr auto globalLogLevel = Debug;
|
|
||||||
#else
|
|
||||||
static constexpr auto globalLogLevel = Warn;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <LogLevel messageType = Info, class... Args>
|
|
||||||
void print(const std::format_string<Args...> fmt, Args... args) {
|
|
||||||
if (messageType >= globalLogLevel) {
|
|
||||||
if (messageType <= Debug) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
std::println(fmt, std::forward<Args>(args)...);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
std::println(fmt, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define panic(fmt, ...) \
|
|
||||||
do { \
|
|
||||||
Util::print<Util::Error>("[FATAL] " fmt __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
exit(-1); \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
#define error(fmt, ...) \
|
|
||||||
do { \
|
|
||||||
Util::print<Util::Error>("[ERROR] " fmt __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
#define warn(fmt, ...) \
|
|
||||||
do { \
|
|
||||||
Util::print<Util::Warn>("[WARN] " fmt __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
#define info(fmt, ...) \
|
|
||||||
do { \
|
|
||||||
Util::print<Util::Info>("[INFO] " fmt __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
#define debug(fmt, ...) \
|
|
||||||
do { \
|
|
||||||
Util::print<Util::Debug>("[DEBUG] " fmt __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
#define trace(fmt, ...) \
|
|
||||||
do { \
|
|
||||||
Util::print<Util::Trace>("[TRACE] " fmt __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
#define always(fmt, ...) \
|
|
||||||
do { \
|
|
||||||
Util::print<Util::Always>(fmt __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
} // namespace Util
|
|
||||||
Reference in New Issue
Block a user