aaaaaaaaa
This commit is contained in:
@@ -82,6 +82,12 @@ u32 Core::StepCPU() {
|
|||||||
void Core::StepRSP(const u32 cpuCycles) {
|
void Core::StepRSP(const u32 cpuCycles) {
|
||||||
MMIO &mmio = mem->mmio;
|
MMIO &mmio = mem->mmio;
|
||||||
|
|
||||||
|
if (mmio.rsp.spStatus.halt) {
|
||||||
|
regs.steps = 0;
|
||||||
|
mmio.rsp.steps = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr u32 cpuRatio = 3, rspRatio = 2;
|
static constexpr u32 cpuRatio = 3, rspRatio = 2;
|
||||||
|
|
||||||
regs.steps += cpuCycles;
|
regs.steps += cpuCycles;
|
||||||
@@ -113,6 +119,7 @@ void Core::Run(const float volumeL, const float volumeR) {
|
|||||||
const u32 taken = StepCPU();
|
const u32 taken = StepCPU();
|
||||||
cycles += taken;
|
cycles += taken;
|
||||||
frameCycles += taken;
|
frameCycles += taken;
|
||||||
|
StepRSP(taken);
|
||||||
Scheduler::GetInstance().Tick(taken);
|
Scheduler::GetInstance().Tick(taken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,6 @@ void Scheduler::HandleEvents() {
|
|||||||
|
|
||||||
while (ticks >= events.top().time) {
|
while (ticks >= events.top().time) {
|
||||||
switch (const auto type = events.top().type) {
|
switch (const auto type = events.top().type) {
|
||||||
case RSP_STEP:
|
|
||||||
n64::Core::GetInstance().StepRSP(1);
|
|
||||||
break;
|
|
||||||
case SI_DMA:
|
case SI_DMA:
|
||||||
si.DMA();
|
si.DMA();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
enum EventType { NONE, RSP_STEP, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE };
|
enum EventType { NONE, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE };
|
||||||
|
|
||||||
struct Event {
|
struct Event {
|
||||||
u64 time;
|
u64 time;
|
||||||
|
|||||||
@@ -93,14 +93,6 @@ u32 Interpreter::Step() {
|
|||||||
|
|
||||||
DecodeExecute(instr);
|
DecodeExecute(instr);
|
||||||
|
|
||||||
if (!mem.mmio.rsp.spStatus.halt) {
|
|
||||||
rspSyncCount++;
|
|
||||||
if (rspSyncCount >= 3)
|
|
||||||
Scheduler::GetInstance().EnqueueRelative(0, RSP_STEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
Scheduler::GetInstance().HandleEvents();
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +124,10 @@ void CachedState::EvictLine(u64 addr) {
|
|||||||
u32 offset;
|
u32 offset;
|
||||||
u32 page = DivideAddr(addr, offset);
|
u32 page = DivideAddr(addr, offset);
|
||||||
|
|
||||||
if (blocks[page])
|
if (blocks[page]) {
|
||||||
blocks[page] = nullptr;
|
blocks[page]->lines[offset].reset();
|
||||||
|
blocks[page].reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Interpreter::ExecuteCached() {
|
u32 Interpreter::ExecuteCached() {
|
||||||
@@ -149,7 +143,6 @@ u32 Interpreter::ExecuteCached() {
|
|||||||
Instruction instr = line->code[i];
|
Instruction instr = line->code[i];
|
||||||
DecodeExecute(instr);
|
DecodeExecute(instr);
|
||||||
|
|
||||||
Scheduler::GetInstance().HandleEvents();
|
|
||||||
// Branch likely with false condition, it wasn't taken so don't execute the delay slot
|
// Branch likely with false condition, it wasn't taken so don't execute the delay slot
|
||||||
if (IsBranchLikely(instr) && !regs.delaySlot)
|
if (IsBranchLikely(instr) && !regs.delaySlot)
|
||||||
break;
|
break;
|
||||||
@@ -187,15 +180,6 @@ u32 Interpreter::ExecuteCached() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mem.mmio.rsp.spStatus.halt) {
|
|
||||||
for (int j = 1; j <= (int)std::floor((double)i / 3); j++) {
|
|
||||||
Scheduler::GetInstance().EnqueueRelative(j * 3, RSP_STEP);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
regs.steps = 0;
|
|
||||||
mem.mmio.rsp.steps = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cachedState.InsertLine(blockAddr, std::make_shared<CachedLine>(code, i, i));
|
cachedState.InsertLine(blockAddr, std::make_shared<CachedLine>(code, i, i));
|
||||||
|
|
||||||
return ExecuteCached();
|
return ExecuteCached();
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct Core;
|
struct Core;
|
||||||
|
|
||||||
static constexpr u32 MAX_INSTRUCTION_PER_LINE = 128;
|
|
||||||
static constexpr u32 MAX_LINES_PER_BLOCK = 1 << 12;
|
static constexpr u32 MAX_LINES_PER_BLOCK = 1 << 12;
|
||||||
|
static constexpr u32 MAX_INSTRUCTION_PER_LINE = MAX_LINES_PER_BLOCK >> 2;
|
||||||
|
|
||||||
struct CachedLine {
|
struct CachedLine {
|
||||||
std::array<Instruction, MAX_INSTRUCTION_PER_LINE> code = {};
|
std::array<Instruction, MAX_INSTRUCTION_PER_LINE> code = {};
|
||||||
@@ -51,14 +51,15 @@ struct Interpreter final {
|
|||||||
cachedState.Reset();
|
cachedState.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CachedState cachedState;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct Cop1;
|
friend struct Cop1;
|
||||||
friend struct Mem;
|
friend struct Mem;
|
||||||
|
|
||||||
void MaybeIdleSkip();
|
void MaybeIdleSkip();
|
||||||
|
|
||||||
CachedState cachedState;
|
|
||||||
|
|
||||||
InstructionCache icache;
|
InstructionCache icache;
|
||||||
DataCache dcache;
|
DataCache dcache;
|
||||||
Registers ®s;
|
Registers ®s;
|
||||||
|
|||||||
+172
-169
@@ -4,75 +4,79 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
RDP::RDP() {
|
RDP::RDP() {
|
||||||
rdram.resize(RDRAM_SIZE);
|
rdram.resize(RDRAM_SIZE);
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RDP::Reset() {
|
void RDP::Reset() {
|
||||||
dpc = {};
|
dpc = {};
|
||||||
dpc.status.raw = 0x80;
|
dpc.status.raw = 0x80;
|
||||||
std::ranges::fill(rdram, 0);
|
std::ranges::fill(rdram, 0);
|
||||||
std::ranges::fill(cmd_buf, 0);
|
std::ranges::fill(cmd_buf, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void RDP::WriteRDRAM<u8>(const size_t idx, const u8 v) {
|
void RDP::WriteRDRAM<u8>(const size_t idx, const u8 v) {
|
||||||
if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] {
|
if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] {
|
||||||
rdram[real] = v;
|
rdram[real] = v;
|
||||||
}
|
Core::GetInstance().interpreter.cachedState.EvictLine(idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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::WriteAccess<u16>(rdram, real, v);
|
||||||
}
|
Core::GetInstance().interpreter.cachedState.EvictLine(idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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::WriteAccess<u32>(rdram, idx, v);
|
||||||
}
|
Core::GetInstance().interpreter.cachedState.EvictLine(idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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::WriteAccess<u64>(rdram, idx, v);
|
||||||
}
|
Core::GetInstance().interpreter.cachedState.EvictLine(idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
u8 RDP::ReadRDRAM<u8>(const size_t idx) {
|
u8 RDP::ReadRDRAM<u8>(const size_t idx) {
|
||||||
if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]]
|
if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]]
|
||||||
return rdram[real];
|
return rdram[real];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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::ReadAccess<u16>(rdram, real);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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::ReadAccess<u32>(rdram, idx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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::ReadAccess<u64>(rdram, idx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int cmd_lens[64] = {2, 2, 2, 2, 2, 2, 2, 2, 8, 12, 24, 28, 24, 28, 40, 44, 2, 2, 2, 2, 2, 2,
|
static const int cmd_lens[64] = {2, 2, 2, 2, 2, 2, 2, 2, 8, 12, 24, 28, 24, 28, 40, 44, 2, 2, 2, 2, 2, 2,
|
||||||
@@ -80,79 +84,78 @@ static const int cmd_lens[64] = {2, 2, 2, 2, 2, 2, 2, 2, 8, 12, 24, 28, 24, 28,
|
|||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
|
||||||
|
|
||||||
auto RDP::Read(const u32 addr) const -> u32 {
|
auto RDP::Read(const u32 addr) const -> u32 {
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0x04100000:
|
case 0x04100000:
|
||||||
return dpc.start;
|
return dpc.start;
|
||||||
case 0x04100004:
|
case 0x04100004:
|
||||||
return dpc.end;
|
return dpc.end;
|
||||||
case 0x04100008:
|
case 0x04100008:
|
||||||
return dpc.current;
|
return dpc.current;
|
||||||
case 0x0410000C:
|
case 0x0410000C:
|
||||||
return dpc.status.raw;
|
return dpc.status.raw;
|
||||||
case 0x04100010:
|
case 0x04100010:
|
||||||
return dpc.clock;
|
return dpc.clock;
|
||||||
case 0x04100014:
|
case 0x04100014:
|
||||||
return dpc.status.cmdBusy;
|
return dpc.status.cmdBusy;
|
||||||
case 0x04100018:
|
case 0x04100018:
|
||||||
return dpc.status.pipeBusy;
|
return dpc.status.pipeBusy;
|
||||||
case 0x0410001C:
|
case 0x0410001C:
|
||||||
return dpc.tmem;
|
return dpc.tmem;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled DP Command Registers read (addr: {:08X})", addr);
|
panic("Unhandled DP Command Registers read (addr: {:08X})", addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RDP::Write(const u32 addr, const u32 val) {
|
void RDP::Write(const u32 addr, const u32 val) {
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0x04100000:
|
case 0x04100000:
|
||||||
WriteStart(val);
|
WriteStart(val);
|
||||||
break;
|
break;
|
||||||
case 0x04100004:
|
case 0x04100004:
|
||||||
WriteEnd(val);
|
WriteEnd(val);
|
||||||
break;
|
break;
|
||||||
case 0x0410000C:
|
case 0x0410000C:
|
||||||
WriteStatus(val);
|
WriteStatus(val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val);
|
panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RDP::WriteStatus(const u32 val) {
|
void RDP::WriteStatus(const u32 val) {
|
||||||
DPCStatusWrite temp{};
|
DPCStatusWrite temp{};
|
||||||
temp.raw = val;
|
temp.raw = val;
|
||||||
bool unfrozen = false;
|
bool unfrozen = false;
|
||||||
#define CLEAR_SET(val, clear, set) \
|
#define CLEAR_SET(val, clear, set) \
|
||||||
do { \
|
do { \
|
||||||
if ((clear)) \
|
if ((clear)) \
|
||||||
(val) = 0; \
|
(val) = 0; \
|
||||||
if ((set)) \
|
if ((set)) \
|
||||||
(val) = 1; \
|
(val) = 1; \
|
||||||
} \
|
} \
|
||||||
while (0)
|
while (0)
|
||||||
|
|
||||||
CLEAR_SET(dpc.status.xbusDmemDma, temp.clearXbusDmemDma, temp.setXbusDmemDma);
|
CLEAR_SET(dpc.status.xbusDmemDma, temp.clearXbusDmemDma, temp.setXbusDmemDma);
|
||||||
if (temp.clearFreeze) {
|
if (temp.clearFreeze) {
|
||||||
dpc.status.freeze = false;
|
dpc.status.freeze = false;
|
||||||
unfrozen = true;
|
unfrozen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp.setFreeze) {
|
if (temp.setFreeze) {
|
||||||
dpc.status.freeze = true;
|
dpc.status.freeze = true;
|
||||||
}
|
}
|
||||||
CLEAR_SET(dpc.status.flush, temp.clearFlush, temp.setFlush);
|
CLEAR_SET(dpc.status.flush, temp.clearFlush, temp.setFlush);
|
||||||
CLEAR_SET(dpc.status.tmemBusy, temp.clearTmem, false);
|
CLEAR_SET(dpc.status.tmemBusy, temp.clearTmem, false);
|
||||||
CLEAR_SET(dpc.status.pipeBusy, temp.clearPipe, false);
|
CLEAR_SET(dpc.status.pipeBusy, temp.clearPipe, false);
|
||||||
CLEAR_SET(dpc.status.cmdBusy, temp.clearCmd, false);
|
CLEAR_SET(dpc.status.cmdBusy, temp.clearCmd, false);
|
||||||
CLEAR_SET(dpc.clock, temp.clearClock, false);
|
CLEAR_SET(dpc.clock, temp.clearClock, false);
|
||||||
|
|
||||||
if (!unfrozen) {
|
if (!unfrozen) {
|
||||||
RunCommand();
|
RunCommand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
FORCE_INLINE void logCommand(u8 cmd) {
|
FORCE_INLINE void logCommand(u8 cmd) {
|
||||||
@@ -197,102 +200,102 @@ FORCE_INLINE void logCommand(u8 cmd) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void RDP::RunCommand() {
|
void RDP::RunCommand() {
|
||||||
n64::Mem& mem = n64::Core::GetMem();
|
n64::Mem &mem = n64::Core::GetMem();
|
||||||
ParallelRDP& parallel = n64::Core::GetInstance().parallel;
|
ParallelRDP ¶llel = n64::Core::GetInstance().parallel;
|
||||||
if (dpc.status.freeze) {
|
if (dpc.status.freeze) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
dpc.status.pipeBusy = true;
|
|
||||||
dpc.status.startGclk = true;
|
|
||||||
if (dpc.end > dpc.current) {
|
|
||||||
dpc.status.freeze = true;
|
|
||||||
|
|
||||||
static int remaining_cmds = 0;
|
|
||||||
|
|
||||||
const u32 current = dpc.current & 0xFFFFF8;
|
|
||||||
const u32 end = dpc.end & 0xFFFFF8;
|
|
||||||
|
|
||||||
const auto len = static_cast<s32>(end) - static_cast<s32>(current);
|
|
||||||
if (len <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (len + remaining_cmds * 4 > COMMAND_BUFFER_SIZE) {
|
|
||||||
panic("Too many RDP commands");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dpc.status.xbusDmemDma) {
|
|
||||||
for (int i = 0; i < len; i += 4) {
|
|
||||||
const u32 cmd = ircolib::ReadAccess<u32>(mem.mmio.rsp.dmem, current + i & 0xFFF);
|
|
||||||
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (end > 0x7FFFFFF || current > 0x7FFFFFF) { // if (end > RDRAM_DSIZE || current > RDRAM_DSIZE)
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < len; i += 4) {
|
|
||||||
const u32 cmd = ircolib::ReadAccess<u32>(rdram, current + i);
|
|
||||||
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
dpc.status.pipeBusy = true;
|
||||||
|
dpc.status.startGclk = true;
|
||||||
|
if (dpc.end > dpc.current) {
|
||||||
|
dpc.status.freeze = true;
|
||||||
|
|
||||||
const int word_len = (len >> 2) + remaining_cmds;
|
static int remaining_cmds = 0;
|
||||||
int buf_index = 0;
|
|
||||||
|
|
||||||
bool processed_all = true;
|
const u32 current = dpc.current & 0xFFFFF8;
|
||||||
|
const u32 end = dpc.end & 0xFFFFF8;
|
||||||
|
|
||||||
while (buf_index < word_len) {
|
const auto len = static_cast<s32>(end) - static_cast<s32>(current);
|
||||||
const u8 cmd = cmd_buf[buf_index] >> 24 & 0x3F;
|
if (len <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
const int cmd_len = cmd_lens[cmd];
|
if (len + remaining_cmds * 4 > COMMAND_BUFFER_SIZE) {
|
||||||
if ((buf_index + cmd_len) * 4 > len + remaining_cmds * 4) {
|
panic("Too many RDP commands");
|
||||||
remaining_cmds = word_len - buf_index;
|
return;
|
||||||
|
|
||||||
u32 tmp[remaining_cmds];
|
|
||||||
for (int i = 0; i < remaining_cmds; i++) {
|
|
||||||
tmp[i] = cmd_buf[buf_index + i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < remaining_cmds; i++) {
|
if (dpc.status.xbusDmemDma) {
|
||||||
cmd_buf[i] = tmp[i];
|
for (int i = 0; i < len; i += 4) {
|
||||||
|
const u32 cmd = ircolib::ReadAccess<u32>(mem.mmio.rsp.dmem, current + i & 0xFFF);
|
||||||
|
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (end > 0x7FFFFFF || current > 0x7FFFFFF) { // if (end > RDRAM_DSIZE || current > RDRAM_DSIZE)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i += 4) {
|
||||||
|
const u32 cmd = ircolib::ReadAccess<u32>(rdram, current + i);
|
||||||
|
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_all = false;
|
const int word_len = (len >> 2) + remaining_cmds;
|
||||||
break;
|
int buf_index = 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd >= 8) {
|
bool processed_all = true;
|
||||||
parallel.EnqueueCommand(cmd_len, &cmd_buf[buf_index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd == 0x29) {
|
while (buf_index < word_len) {
|
||||||
OnFullSync();
|
const u8 cmd = cmd_buf[buf_index] >> 24 & 0x3F;
|
||||||
}
|
|
||||||
|
|
||||||
buf_index += cmd_len;
|
const int cmd_len = cmd_lens[cmd];
|
||||||
|
if ((buf_index + cmd_len) * 4 > len + remaining_cmds * 4) {
|
||||||
|
remaining_cmds = word_len - buf_index;
|
||||||
|
|
||||||
|
u32 tmp[remaining_cmds];
|
||||||
|
for (int i = 0; i < remaining_cmds; i++) {
|
||||||
|
tmp[i] = cmd_buf[buf_index + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < remaining_cmds; i++) {
|
||||||
|
cmd_buf[i] = tmp[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
processed_all = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd >= 8) {
|
||||||
|
parallel.EnqueueCommand(cmd_len, &cmd_buf[buf_index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == 0x29) {
|
||||||
|
OnFullSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_index += cmd_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processed_all) {
|
||||||
|
remaining_cmds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dpc.current = end;
|
||||||
|
dpc.end = end;
|
||||||
|
dpc.status.freeze = false;
|
||||||
}
|
}
|
||||||
|
dpc.status.cbufReady = true;
|
||||||
if (processed_all) {
|
|
||||||
remaining_cmds = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dpc.current = end;
|
|
||||||
dpc.end = end;
|
|
||||||
dpc.status.freeze = false;
|
|
||||||
}
|
|
||||||
dpc.status.cbufReady = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RDP::OnFullSync() {
|
void RDP::OnFullSync() {
|
||||||
n64::Mem& mem = n64::Core::GetMem();
|
n64::Mem &mem = n64::Core::GetMem();
|
||||||
ParallelRDP& parallel = n64::Core::GetInstance().parallel;
|
ParallelRDP ¶llel = n64::Core::GetInstance().parallel;
|
||||||
|
|
||||||
parallel.OnFullSync();
|
parallel.OnFullSync();
|
||||||
|
|
||||||
dpc.status.pipeBusy = false;
|
dpc.status.pipeBusy = false;
|
||||||
dpc.status.startGclk = false;
|
dpc.status.startGclk = false;
|
||||||
dpc.status.cbufReady = false;
|
dpc.status.cbufReady = false;
|
||||||
mem.mmio.mi.InterruptRaise(MI::Interrupt::DP);
|
mem.mmio.mi.InterruptRaise(MI::Interrupt::DP);
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1311,6 +1311,7 @@ void Cop1::swc1(const Instruction instr) {
|
|||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
mem.Write<u32>(physical, FGR_T<u32>(regs.cop0.status, instr.ft()));
|
mem.Write<u32>(physical, FGR_T<u32>(regs.cop0.status, instr.ft()));
|
||||||
|
Core::GetInstance().interpreter.cachedState.EvictLine(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1338,6 +1339,7 @@ void Cop1::sdc1(const Instruction instr) {
|
|||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
mem.Write(physical, FGR_T<u64>(regs.cop0.status, instr.ft()));
|
mem.Write(physical, FGR_T<u64>(regs.cop0.status, instr.ft()));
|
||||||
|
Core::GetInstance().interpreter.cachedState.EvictLine(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,18 @@ static bool InstrEndsBlock(const Instruction instr) {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
case Instruction::COP0:
|
||||||
|
switch (instr.cop_rs()) {
|
||||||
|
case 0x10 ... 0x1F:
|
||||||
|
switch (instr.cop_funct()) {
|
||||||
|
case 0x18: // eret
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user