mirror of
https://github.com/kmc-jp/n64-emu.git
synced 2025-04-02 10:21:43 -04:00
263 lines
5.8 KiB
C++
263 lines
5.8 KiB
C++
#ifndef CPU_COP0_H
|
|
#define CPU_COP0_H
|
|
|
|
#include "utils/pack.h"
|
|
#include <cstdint>
|
|
|
|
namespace N64 {
|
|
|
|
union entry_lo0_t {
|
|
uint32_t raw;
|
|
PACK(struct {
|
|
unsigned global : 1;
|
|
unsigned v : 1;
|
|
unsigned d : 1;
|
|
unsigned c : 3;
|
|
unsigned pfn : 20;
|
|
unsigned : 6;
|
|
});
|
|
};
|
|
|
|
static_assert(sizeof(entry_lo0_t) == 4);
|
|
|
|
union entry_lo1_t {
|
|
uint32_t raw;
|
|
PACK(struct {
|
|
unsigned global : 1;
|
|
unsigned v : 1;
|
|
unsigned d : 1;
|
|
unsigned c : 3;
|
|
unsigned pfn : 20;
|
|
unsigned : 6;
|
|
});
|
|
};
|
|
|
|
static_assert(sizeof(entry_lo1_t) == 4);
|
|
|
|
// FIXME: 64bit?
|
|
PACK(union entry_hi_t {
|
|
uint32_t raw;
|
|
PACK(struct {
|
|
unsigned asid : 8;
|
|
unsigned : 4;
|
|
unsigned g : 1;
|
|
unsigned vpn2 : 19;
|
|
});
|
|
});
|
|
|
|
static_assert(sizeof(entry_hi_t) == 4);
|
|
|
|
namespace Cpu {
|
|
|
|
namespace Cop0Reg {
|
|
enum {
|
|
INDEX = 0,
|
|
RANDOM = 1,
|
|
ENTRY_LO0 = 2,
|
|
ENTRY_LO1 = 3,
|
|
CONTEXT = 4,
|
|
PAGE_MASK = 5,
|
|
WIRED = 6,
|
|
BAD_VADDR = 8,
|
|
COUNT = 9,
|
|
ENTRY_HI = 10,
|
|
COMPARE = 11,
|
|
STATUS = 12,
|
|
CAUSE = 13,
|
|
EPC = 14,
|
|
PRID = 15,
|
|
CONFIG = 16,
|
|
LL_ADDR = 17,
|
|
WATCH_LO = 18,
|
|
WATCH_HI = 19,
|
|
X_CONTEXT = 20,
|
|
PARITY_ERROR = 26,
|
|
CACHE_ERROR = 27,
|
|
TAG_LO = 28,
|
|
TAG_HI = 29,
|
|
ERROR_EPC = 30,
|
|
};
|
|
}
|
|
constexpr std::string_view UNUSED_COP0_REG_NAME = "unused";
|
|
|
|
constexpr std::array<std::string_view, 32> COP0_REG_NAMES = {
|
|
"Index",
|
|
"Random",
|
|
"EntryLo0",
|
|
"EntryLo1",
|
|
"Context",
|
|
"PageMask",
|
|
"Wired",
|
|
UNUSED_COP0_REG_NAME,
|
|
"BadVAddr",
|
|
"Count",
|
|
"EntryHi",
|
|
"Compare",
|
|
"Status",
|
|
"Cause",
|
|
"EPC",
|
|
"PRId",
|
|
"Config",
|
|
"LLAddr",
|
|
"WatchLo",
|
|
"WatchHi",
|
|
"XContext",
|
|
UNUSED_COP0_REG_NAME,
|
|
UNUSED_COP0_REG_NAME,
|
|
UNUSED_COP0_REG_NAME,
|
|
UNUSED_COP0_REG_NAME,
|
|
UNUSED_COP0_REG_NAME,
|
|
"ECC",
|
|
"CacheErr",
|
|
"TagLo",
|
|
"TagHi",
|
|
"ErrEPC",
|
|
UNUSED_COP0_REG_NAME,
|
|
};
|
|
|
|
// FIXME: bit fieldの順番があってるか確認
|
|
union cop0_cause_t {
|
|
uint32_t raw;
|
|
PACK(struct {
|
|
unsigned : 8;
|
|
unsigned interrupt_pending : 8;
|
|
unsigned : 16;
|
|
});
|
|
PACK(struct {
|
|
unsigned : 2;
|
|
unsigned exception_code : 5;
|
|
unsigned : 1;
|
|
unsigned ip0 : 1;
|
|
unsigned ip1 : 1;
|
|
unsigned ip2 : 1;
|
|
unsigned ip3 : 1;
|
|
unsigned ip4 : 1;
|
|
unsigned ip5 : 1;
|
|
unsigned ip6 : 1;
|
|
unsigned ip7 : 1;
|
|
unsigned : 12;
|
|
unsigned coprocessor_error : 2;
|
|
unsigned : 1;
|
|
unsigned branch_delay : 1;
|
|
});
|
|
};
|
|
|
|
static_assert(sizeof(cop0_cause_t) == 4, "cop0_cause_t must be 32bit");
|
|
|
|
// FIXME: bit fieldの順番があってるか確認
|
|
union cop0_x_context_t {
|
|
uint64_t raw;
|
|
/* FIXME: MSVCだとrでワード境界を超えて、16bytesになってしまう
|
|
https://learn.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-170
|
|
PACK(struct {
|
|
unsigned : 4;
|
|
unsigned badvpn2 : 27;
|
|
unsigned r : 2;
|
|
unsigned ptebase : 31;
|
|
});
|
|
*/
|
|
};
|
|
|
|
static_assert(sizeof(cop0_x_context_t) == 8, "cop0_x_context_t must be 64bit");
|
|
|
|
// FIXME: bit fieldの順番があってるか確認
|
|
union cop0_status_t {
|
|
uint32_t raw;
|
|
PACK(struct {
|
|
unsigned ie : 1;
|
|
unsigned exl : 1;
|
|
unsigned erl : 1;
|
|
unsigned ksu : 2;
|
|
unsigned ux : 1;
|
|
unsigned sx : 1;
|
|
unsigned kx : 1;
|
|
unsigned im : 8; // interrupt mask
|
|
unsigned ds : 9;
|
|
unsigned re : 1;
|
|
unsigned fr : 1;
|
|
unsigned rp : 1;
|
|
unsigned cu0 : 1;
|
|
unsigned cu1 : 1;
|
|
unsigned cu2 : 1;
|
|
unsigned cu3 : 1;
|
|
});
|
|
struct PACK({
|
|
unsigned : 16;
|
|
unsigned de : 1;
|
|
unsigned ce : 1;
|
|
unsigned ch : 1;
|
|
unsigned : 1;
|
|
unsigned sr : 1;
|
|
unsigned ts : 1;
|
|
unsigned bev : 1;
|
|
unsigned : 1;
|
|
unsigned its : 1;
|
|
unsigned : 7;
|
|
});
|
|
};
|
|
|
|
static_assert(sizeof(cop0_status_t) == 4, "cop0_status_t must be 32bit");
|
|
|
|
class Cop0 {
|
|
class Reg {
|
|
public:
|
|
// COP0 registers
|
|
// The on-chip system control coprocessor (CP0) uses 25 registers.
|
|
// These registers are 32 bits wide except for EntryHi, XContext,
|
|
// EPC, and ErrorPC, which are 64 bits wide.
|
|
// https://ultra64.ca/files/documentation/silicon-graphics/SGI_R4300_RISC_Processor_Specification_REV2.2.pdf
|
|
uint32_t index;
|
|
uint32_t random;
|
|
entry_lo0_t entry_lo0;
|
|
entry_lo1_t entry_lo1;
|
|
uint32_t context; // TODO: refine type?
|
|
uint32_t page_mask; // TODO: refine type?
|
|
uint32_t wired;
|
|
// 7th register is unknown
|
|
uint32_t bad_vaddr;
|
|
uint32_t count;
|
|
entry_hi_t entry_hi; // 64bit
|
|
uint32_t compare;
|
|
cop0_status_t status; // TODO: refine type?
|
|
cop0_cause_t cause; // TODO: refine type?F
|
|
uint64_t epc; // 64bit
|
|
uint32_t prid;
|
|
uint32_t config;
|
|
uint32_t lladdr;
|
|
uint32_t watch_lo; // TODO: refine type?
|
|
uint32_t watch_hi;
|
|
cop0_x_context_t xcontext; // 64bit TODO: refine type?
|
|
// 21st register is unknown
|
|
// 22st register is unknown
|
|
// 23st register is unknown
|
|
// 24st register is unknown
|
|
// 25st register is unknown
|
|
uint32_t parity_error;
|
|
uint32_t cache_error;
|
|
uint32_t tag_lo;
|
|
uint32_t tag_hi;
|
|
uint64_t error_epc; // 64bit
|
|
// 31st regiser is unknwon
|
|
|
|
uint64_t read(uint8_t reg_num) const;
|
|
void write(uint8_t reg_num, uint64_t value);
|
|
};
|
|
|
|
public:
|
|
Reg reg;
|
|
// Set true iff LLAddr is set
|
|
bool llbit;
|
|
|
|
Cop0() {}
|
|
|
|
void reset();
|
|
|
|
void dump();
|
|
|
|
// void on_status_updated();
|
|
};
|
|
|
|
} // namespace Cpu
|
|
} // namespace N64
|
|
|
|
#endif
|