mirror of
https://github.com/google0101-ryan/Emotional.git
synced 2024-06-16 03:08:18 -04:00
Started tidying, first SIF transfer
This commit is contained in:
parent
923d19a971
commit
da6fdef63a
|
@ -8,19 +8,19 @@
|
|||
#include <emu/cpu/ee/vu.h>
|
||||
#include <emu/cpu/iop/cpu.h>
|
||||
|
||||
Scheduler::Event vsync_event;
|
||||
|
||||
#include <chrono>
|
||||
#include <chrono> // NOLINT [build/c++11]
|
||||
#include <iostream>
|
||||
|
||||
Scheduler::Event vsync_event;
|
||||
|
||||
std::chrono::steady_clock::time_point first_tp;
|
||||
unsigned long frame_count = 0;
|
||||
uint64_t frame_count = 0;
|
||||
|
||||
std::chrono::duration<double> uptime()
|
||||
{
|
||||
if (first_tp == std::chrono::steady_clock::time_point{})
|
||||
return std::chrono::duration<double>{0};
|
||||
|
||||
|
||||
return std::chrono::steady_clock::now() - first_tp;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ double fps()
|
|||
|
||||
if (uptime_sec == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
return frame_count / uptime_sec;
|
||||
}
|
||||
|
||||
|
@ -56,10 +56,10 @@ void System::LoadBios(std::string biosName)
|
|||
|
||||
uint8_t* rom = new uint8_t[fSize];
|
||||
|
||||
file.read((char*)rom, fSize);
|
||||
file.read(reinterpret_cast<char*>(rom), fSize);
|
||||
|
||||
Bus::LoadBios(rom);
|
||||
|
||||
|
||||
delete[] rom;
|
||||
|
||||
printf("[emu/Sys]: Loaded BIOS %s\n", biosName.c_str());
|
||||
|
|
|
@ -17,4 +17,4 @@ void Reset();
|
|||
void Run();
|
||||
void Dump();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -246,6 +246,7 @@ private:
|
|||
void EmitBLTZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitBGEZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
void EmitBLTZL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitBGEZL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x03
|
||||
|
||||
void EmitMFLO1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
void EmitMULT1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
|
|
|
@ -1,18 +1,46 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include "dmac.hpp"
|
||||
#include <emu/cpu/ee/dmac.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <emu/sched/scheduler.h>
|
||||
#include <emu/dev/sif.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
namespace DMAC
|
||||
{
|
||||
|
||||
|
||||
union DSTAT
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t channel_irq : 10; /* Clear with 1 */
|
||||
uint32_t : 3;
|
||||
uint32_t dma_stall : 1; /* Clear with 1 */
|
||||
uint32_t mfifo_empty : 1; /* Clear with 1 */
|
||||
uint32_t bus_error : 1; /* Clear with 1 */
|
||||
uint32_t channel_irq_mask : 10; /* Reverse with 1 */
|
||||
uint32_t : 3;
|
||||
uint32_t stall_irq_mask : 1; /* Reverse with 1 */
|
||||
uint32_t mfifo_irq_mask : 1; /* Reverse with 1 */
|
||||
uint32_t : 1;
|
||||
};
|
||||
/* If you notice above the lower 16bits are cleared when 1 is written to them
|
||||
while the upper 16bits are reversed. So I'm making this struct to better
|
||||
implement this behaviour */
|
||||
struct
|
||||
{
|
||||
uint32_t clear : 16;
|
||||
uint32_t reverse : 16;
|
||||
};
|
||||
} stat;
|
||||
|
||||
union DN_SADR
|
||||
{
|
||||
uint32_t data;
|
||||
|
@ -51,6 +79,7 @@ struct Channel
|
|||
} channels[10];
|
||||
|
||||
uint32_t ctrl;
|
||||
uint32_t d_enable = 0x1201;
|
||||
|
||||
union DMATag
|
||||
{
|
||||
|
@ -73,6 +102,7 @@ const char* REG_NAMES[] =
|
|||
{
|
||||
"CHCR",
|
||||
"MADR",
|
||||
"QWC",
|
||||
"TADR",
|
||||
"ASR0",
|
||||
"ASR1",
|
||||
|
@ -214,31 +244,54 @@ void WriteIPUTOChannel(uint32_t addr, uint32_t data)
|
|||
}
|
||||
}
|
||||
|
||||
bool sif0_ongoing_transfer = false, fetching_sif0_tag = true;
|
||||
DMATag sif0_tag;
|
||||
|
||||
void HandleSIF0Transfer()
|
||||
{
|
||||
auto& c = channels[5];
|
||||
|
||||
if (channels[5].qwc > 0)
|
||||
fetching_sif0_tag = true;
|
||||
|
||||
if (!sif0_ongoing_transfer)
|
||||
return;
|
||||
|
||||
if (fetching_sif0_tag)
|
||||
{
|
||||
if (SIF::FIFO0_size() >= 2)
|
||||
{
|
||||
printf("Fetching DMATag\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sif0_ongoing_transfer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DMATag tag;
|
||||
if (SIF::FIFO0_size() >= 2)
|
||||
}
|
||||
|
||||
if (sif0_ongoing_transfer)
|
||||
{
|
||||
Scheduler::Event sif0_evt;
|
||||
sif0_evt.cycles_from_now = 2;
|
||||
sif0_evt.func = HandleSIF0Transfer;
|
||||
sif0_evt.name = "SIF0 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif0_evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[emu/DMAC]: Transfer ended on SIF0 channel\n");
|
||||
|
||||
stat.channel_irq |= (1 << 5);
|
||||
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
{
|
||||
printf("Oh crap, I gotta do stuff now\n");
|
||||
printf("[emu/DMAC]: Fire interrupt\n");
|
||||
exit(1);
|
||||
}
|
||||
else if (c.chcr.start) // Make sure our transfer wasn't canceled by the EE
|
||||
{
|
||||
// Try again in two cycles to see if SIF's fifo0 has filled
|
||||
Scheduler::Event sif0_evt;
|
||||
sif0_evt.cycles_from_now = 2;
|
||||
sif0_evt.func = HandleSIF0Transfer;
|
||||
sif0_evt.name = "SIF0 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif0_evt);
|
||||
}
|
||||
c.chcr.start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,6 +315,8 @@ void WriteSIF0Channel(uint32_t addr, uint32_t data)
|
|||
sif0_evt.name = "SIF0 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif0_evt);
|
||||
|
||||
sif0_ongoing_transfer = true;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
|
@ -285,6 +340,110 @@ void WriteSIF0Channel(uint32_t addr, uint32_t data)
|
|||
}
|
||||
}
|
||||
|
||||
bool fetching_tag = true, ongoing_transfer = false;
|
||||
|
||||
DMATag tag;
|
||||
|
||||
void HandleSIF1Transfer()
|
||||
{
|
||||
auto& c = channels[6];
|
||||
|
||||
if (!ongoing_transfer)
|
||||
return;
|
||||
|
||||
if (fetching_tag)
|
||||
{
|
||||
tag.value = Bus::Read128(c.tadr).u128;
|
||||
|
||||
printf("[emu/DMAC]: Found tag on SIF1 %s at 0x%08x\n", print_128({tag.value}), c.tadr);
|
||||
|
||||
c.qwc = tag.qwc;
|
||||
|
||||
switch (tag.tag_id)
|
||||
{
|
||||
case 0:
|
||||
c.madr = tag.addr;
|
||||
c.tadr += 16;
|
||||
tag.irq = true; // End the transfer and fire an irq
|
||||
break;
|
||||
case 3:
|
||||
c.madr = tag.addr;
|
||||
c.tadr += 16;
|
||||
break;
|
||||
default:
|
||||
printf("[emu/DMAC]: unknown tag mode %d\n", tag.tag_id);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fetching_tag = false;
|
||||
|
||||
int cycles_til_transfer = tag.qwc * 2; // Each qword transfered takes two cycles, so we transfer all at once that many cycles later
|
||||
|
||||
Scheduler::Event sif1_evt;
|
||||
sif1_evt.cycles_from_now = cycles_til_transfer;
|
||||
sif1_evt.func = HandleSIF1Transfer;
|
||||
sif1_evt.name = "SIF1 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif1_evt);
|
||||
|
||||
if (c.chcr.tte)
|
||||
{
|
||||
uint128_t qword = {tag.value};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
SIF::WriteFIFO1(qword.u32[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tag.qwc; i++)
|
||||
{
|
||||
uint128_t qword = Bus::Read128(c.madr);
|
||||
c.madr += 16;
|
||||
|
||||
printf("[emu/DMAC]: Transfering qword %s\n", print_128(qword));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
SIF::WriteFIFO1(qword.u32[i]);
|
||||
}
|
||||
}
|
||||
|
||||
c.qwc = 0;
|
||||
|
||||
fetching_tag = true;
|
||||
|
||||
if (tag.irq)
|
||||
ongoing_transfer = false;
|
||||
}
|
||||
|
||||
if (ongoing_transfer)
|
||||
{
|
||||
Scheduler::Event sif1_evt;
|
||||
sif1_evt.cycles_from_now = 2;
|
||||
sif1_evt.func = HandleSIF1Transfer;
|
||||
sif1_evt.name = "SIF1 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif1_evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[emu/DMAC]: Transfer ended on SIF1 channel\n");
|
||||
|
||||
stat.channel_irq |= (1 << 6);
|
||||
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
{
|
||||
printf("[emu/DMAC]: Fire interrupt\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
c.chcr.start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteSIF1Channel(uint32_t addr, uint32_t data)
|
||||
{
|
||||
printf("[emu/DMAC]: Writing 0x%08x to %s of SIF1 channel\n", data, REG_NAMES[(addr >> 4) & 0xf]);
|
||||
|
@ -293,8 +452,21 @@ void WriteSIF1Channel(uint32_t addr, uint32_t data)
|
|||
{
|
||||
case 0x00:
|
||||
channels[6].chcr.data = data;
|
||||
if (channels[5].chcr.start)
|
||||
if (channels[6].chcr.start && (ctrl & 1))
|
||||
{
|
||||
printf("[emu/DMAC]: Starting SIF1 transfer\n");
|
||||
|
||||
// We schedule the transfer 1 cycle from now
|
||||
// This is because the DMAC ticks at half the speed of the EE
|
||||
Scheduler::Event sif1_evt;
|
||||
sif1_evt.cycles_from_now = 1;
|
||||
sif1_evt.func = HandleSIF1Transfer;
|
||||
sif1_evt.name = "SIF1 DMA transfer";
|
||||
|
||||
Scheduler::ScheduleEvent(sif1_evt);
|
||||
|
||||
ongoing_transfer = true;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
channels[6].madr = data;
|
||||
|
@ -368,7 +540,7 @@ void WriteSPRFROMChannel(uint32_t addr, uint32_t data)
|
|||
case 0x80:
|
||||
channels[8].sadr.data = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void WriteSPRTOChannel(uint32_t addr, uint32_t data)
|
||||
{
|
||||
|
@ -408,39 +580,40 @@ uint32_t ReadSIF0Channel(uint32_t addr)
|
|||
}
|
||||
}
|
||||
|
||||
union DSTAT
|
||||
uint32_t ReadSIF1Channel(uint32_t addr)
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t channel_irq : 10; /* Clear with 1 */
|
||||
uint32_t : 3;
|
||||
uint32_t dma_stall : 1; /* Clear with 1 */
|
||||
uint32_t mfifo_empty : 1; /* Clear with 1 */
|
||||
uint32_t bus_error : 1; /* Clear with 1 */
|
||||
uint32_t channel_irq_mask : 10; /* Reverse with 1 */
|
||||
uint32_t : 3;
|
||||
uint32_t stall_irq_mask : 1; /* Reverse with 1 */
|
||||
uint32_t mfifo_irq_mask : 1; /* Reverse with 1 */
|
||||
uint32_t : 1;
|
||||
};
|
||||
/* If you notice above the lower 16bits are cleared when 1 is written to them
|
||||
while the upper 16bits are reversed. So I'm making this struct to better
|
||||
implement this behaviour */
|
||||
struct
|
||||
{
|
||||
uint32_t clear : 16;
|
||||
uint32_t reverse : 16;
|
||||
};
|
||||
} stat;
|
||||
switch (addr & 0xff)
|
||||
{
|
||||
case 0x00:
|
||||
return channels[6].chcr.data;
|
||||
case 0x20:
|
||||
return channels[6].qwc;
|
||||
case 0x30:
|
||||
return channels[6].tadr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ReadDENABLE()
|
||||
{
|
||||
return d_enable;
|
||||
}
|
||||
|
||||
void WriteDENABLE(uint32_t data)
|
||||
{
|
||||
d_enable = data;
|
||||
}
|
||||
|
||||
uint32_t dpcr;
|
||||
uint32_t sqwc;
|
||||
|
||||
void WriteDSTAT(uint32_t data)
|
||||
{
|
||||
printf("[emu/DMAC]: Writing 0x%08x to D_STAT\n", data);
|
||||
|
||||
stat.clear &= ~(data & 0xffff);
|
||||
stat.reverse ^= (data >> 16);
|
||||
|
||||
printf("0x%08x\n", stat.value);
|
||||
}
|
||||
|
||||
uint32_t ReadDSTAT()
|
||||
|
@ -472,4 +645,5 @@ void WriteSQWC(uint32_t data)
|
|||
{
|
||||
sqwc = data;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DMAC
|
||||
|
|
|
@ -20,6 +20,10 @@ void WriteSPRFROMChannel(uint32_t addr, uint32_t data);
|
|||
void WriteSPRTOChannel(uint32_t addr, uint32_t data);
|
||||
|
||||
uint32_t ReadSIF0Channel(uint32_t addr);
|
||||
uint32_t ReadSIF1Channel(uint32_t addr);
|
||||
|
||||
uint32_t ReadDENABLE();
|
||||
void WriteDENABLE(uint32_t data);
|
||||
|
||||
void WriteDSTAT(uint32_t data);
|
||||
uint32_t ReadDSTAT();
|
||||
|
@ -32,4 +36,4 @@ uint32_t ReadDPCR();
|
|||
|
||||
void WriteSQWC(uint32_t data);
|
||||
|
||||
}
|
||||
} // namespace DMAC
|
||||
|
|
|
@ -79,11 +79,11 @@ void EE_JIT::Emitter::EmitMovCond(IRInstruction i)
|
|||
|
||||
if (i.mov_cond == IRInstruction::MovCond::N)
|
||||
{
|
||||
cg->jne(end);
|
||||
cg->je(end);
|
||||
}
|
||||
else
|
||||
{
|
||||
cg->je(end);
|
||||
cg->jne(end);
|
||||
}
|
||||
|
||||
cg->mov(ee_src, cg->qword[cg->rbp + src_offset]);
|
||||
|
@ -1629,7 +1629,7 @@ void EE_JIT::Emitter::EnterDispatcher()
|
|||
dispatcher_entry();
|
||||
}
|
||||
|
||||
const uint8_t *EE_JIT::Emitter::GetFreeBase()
|
||||
uint8_t *EE_JIT::Emitter::GetFreeBase()
|
||||
{
|
||||
return cg->getCurr();
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
cg = new Xbyak::CodeGenerator(0xffffffff, base);
|
||||
}
|
||||
|
||||
const uint8_t* GetFreeBase();
|
||||
uint8_t* GetFreeBase();
|
||||
};
|
||||
|
||||
extern Emitter* emit;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <app/Application.h>
|
||||
#include <emu/cpu/iop/cpu.h>
|
||||
|
||||
#include <cstring>
|
||||
#include "cpu.h"
|
||||
|
||||
uint32_t exception_addr[2] = { 0x80000080, 0xBFC00180 };
|
||||
|
||||
|
@ -217,7 +221,7 @@ void CPU::Dump()
|
|||
|
||||
bool CPU::IntPending()
|
||||
{
|
||||
bool pending = false;
|
||||
bool pending = Bus::I_CTRL && (Bus::I_STAT & Bus::I_MASK);
|
||||
Cop0.cause.IP = (Cop0.cause.IP & ~0x4) | (pending << 2);
|
||||
|
||||
bool enabled = Cop0.status.IEc && (Cop0.status.Im & Cop0.cause.IP);
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <emu/cpu/iop/opcode.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
|
@ -15,10 +19,10 @@ private:
|
|||
bool last_instruction_was_lwl = false;
|
||||
bool last_instruction_was_lwr = false;
|
||||
|
||||
union COP0STAT
|
||||
union COP0STAT
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
struct
|
||||
{
|
||||
uint32_t IEc : 1; /* Interrupt Enable (current) */
|
||||
uint32_t KUc : 1; /* Kernel-User Mode (current) */
|
||||
|
@ -40,10 +44,10 @@ private:
|
|||
};
|
||||
};
|
||||
|
||||
union COP0CAUSE
|
||||
union COP0CAUSE
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
struct
|
||||
{
|
||||
uint32_t : 2;
|
||||
uint32_t excode : 5; /* Exception Code */
|
||||
|
@ -59,7 +63,7 @@ private:
|
|||
union COP0
|
||||
{
|
||||
uint32_t regs[32] = {};
|
||||
struct
|
||||
struct
|
||||
{
|
||||
uint32_t r0;
|
||||
uint32_t r1;
|
||||
|
@ -167,72 +171,72 @@ private:
|
|||
write_back.data = value;
|
||||
}
|
||||
|
||||
void op_special(); // 0x00
|
||||
void op_bcond(); // 0x01
|
||||
void op_j(); // 0x02
|
||||
void op_jal(); // 0x03
|
||||
void op_beq(); // 0x04
|
||||
void op_bne(); // 0x05
|
||||
void op_blez(); // 0x06
|
||||
void op_bgtz(); // 0x07
|
||||
void op_addi(); // 0x08
|
||||
void op_addiu(); // 0x09
|
||||
void op_slti(); // 0x0A
|
||||
void op_sltiu(); // 0x0B
|
||||
void op_andi(); // 0x0C
|
||||
void op_ori(); // 0x0D
|
||||
void op_xori(); // 0x0E
|
||||
void op_lui(); // 0x0F
|
||||
void op_cop0(); // 0x10
|
||||
void op_cop2(); // 0x12
|
||||
void op_lb(); // 0x20
|
||||
void op_lh(); // 0x21
|
||||
void op_lwl(); // 0x22
|
||||
void op_lw(); // 0x23
|
||||
void op_lbu(); // 0x24
|
||||
void op_lhu(); // 0x25
|
||||
void op_lwr(); // 0x26
|
||||
void op_sb(); // 0x28
|
||||
void op_sh(); // 0x29
|
||||
void op_swl(); // 0x2A
|
||||
void op_sw(); // 0x2B
|
||||
void op_swr(); // 0x2E
|
||||
void op_special(); // 0x00
|
||||
void op_bcond(); // 0x01
|
||||
void op_j(); // 0x02
|
||||
void op_jal(); // 0x03
|
||||
void op_beq(); // 0x04
|
||||
void op_bne(); // 0x05
|
||||
void op_blez(); // 0x06
|
||||
void op_bgtz(); // 0x07
|
||||
void op_addi(); // 0x08
|
||||
void op_addiu(); // 0x09
|
||||
void op_slti(); // 0x0A
|
||||
void op_sltiu(); // 0x0B
|
||||
void op_andi(); // 0x0C
|
||||
void op_ori(); // 0x0D
|
||||
void op_xori(); // 0x0E
|
||||
void op_lui(); // 0x0F
|
||||
void op_cop0(); // 0x10
|
||||
void op_cop2(); // 0x12
|
||||
void op_lb(); // 0x20
|
||||
void op_lh(); // 0x21
|
||||
void op_lwl(); // 0x22
|
||||
void op_lw(); // 0x23
|
||||
void op_lbu(); // 0x24
|
||||
void op_lhu(); // 0x25
|
||||
void op_lwr(); // 0x26
|
||||
void op_sb(); // 0x28
|
||||
void op_sh(); // 0x29
|
||||
void op_swl(); // 0x2A
|
||||
void op_sw(); // 0x2B
|
||||
void op_swr(); // 0x2E
|
||||
|
||||
// special
|
||||
// special
|
||||
|
||||
void op_sll(); // 0x00
|
||||
void op_srl(); // 0x02
|
||||
void op_sra(); // 0x03
|
||||
void op_sllv(); // 0x04
|
||||
void op_srlv(); // 0x06
|
||||
void op_srav(); // 0x07
|
||||
void op_jr(); // 0x08
|
||||
void op_jalr(); // 0x09
|
||||
void op_syscall(); // 0x0C
|
||||
void op_mfhi(); // 0x10
|
||||
void op_mthi(); // 0x11
|
||||
void op_mflo(); // 0x12
|
||||
void op_mtlo(); // 0x13
|
||||
void op_mult(); // 0x18
|
||||
void op_multu(); // 0x19
|
||||
void op_div(); // 0x1A
|
||||
void op_divu(); // 0x1B
|
||||
void op_add(); // 0x20
|
||||
void op_addu(); // 0x21
|
||||
void op_sub(); // 0x22
|
||||
void op_subu(); // 0x23
|
||||
void op_and(); // 0x24
|
||||
void op_or(); // 0x25
|
||||
void op_xor(); // 0x26
|
||||
void op_nor(); // 0x27
|
||||
void op_slt(); // 0x2A
|
||||
void op_sltu(); // 0x2B
|
||||
void op_sll(); // 0x00
|
||||
void op_srl(); // 0x02
|
||||
void op_sra(); // 0x03
|
||||
void op_sllv(); // 0x04
|
||||
void op_srlv(); // 0x06
|
||||
void op_srav(); // 0x07
|
||||
void op_jr(); // 0x08
|
||||
void op_jalr(); // 0x09
|
||||
void op_syscall(); // 0x0C
|
||||
void op_mfhi(); // 0x10
|
||||
void op_mthi(); // 0x11
|
||||
void op_mflo(); // 0x12
|
||||
void op_mtlo(); // 0x13
|
||||
void op_mult(); // 0x18
|
||||
void op_multu(); // 0x19
|
||||
void op_div(); // 0x1A
|
||||
void op_divu(); // 0x1B
|
||||
void op_add(); // 0x20
|
||||
void op_addu(); // 0x21
|
||||
void op_sub(); // 0x22
|
||||
void op_subu(); // 0x23
|
||||
void op_and(); // 0x24
|
||||
void op_or(); // 0x25
|
||||
void op_xor(); // 0x26
|
||||
void op_nor(); // 0x27
|
||||
void op_slt(); // 0x2A
|
||||
void op_sltu(); // 0x2B
|
||||
|
||||
// cop0
|
||||
// cop0
|
||||
|
||||
void op_mfc0(); // 0x00
|
||||
void op_mtc0(); // 0x04
|
||||
void op_rfe(); // 0x10
|
||||
void op_mfc0(); // 0x00
|
||||
void op_mtc0(); // 0x04
|
||||
void op_rfe(); // 0x10
|
||||
|
||||
void direct_jump();
|
||||
void handle_load_delay();
|
||||
|
@ -245,7 +249,7 @@ private:
|
|||
bool can_disassemble = false;
|
||||
std::ofstream console;
|
||||
|
||||
enum class Exception
|
||||
enum class Exception
|
||||
{
|
||||
Interrupt = 0x0,
|
||||
ReadError = 0x4,
|
||||
|
@ -278,4 +282,4 @@ void Clock(int cycles);
|
|||
void Reset();
|
||||
void Dump();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +1,83 @@
|
|||
#include "dma.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <emu/sched/scheduler.h>
|
||||
#include <emu/dev/sif.h>
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <cassert>
|
||||
|
||||
union DICR2
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t tag : 13;
|
||||
uint32_t : 3;
|
||||
uint32_t mask : 6;
|
||||
uint32_t : 2;
|
||||
uint32_t flags : 6;
|
||||
uint32_t : 2;
|
||||
};
|
||||
} dicr2 = {0};
|
||||
|
||||
uint32_t dpcr;
|
||||
uint32_t dpcr2;
|
||||
bool dmacen = true;
|
||||
uint32_t dicr = 0;
|
||||
uint32_t dicr2 = 0;
|
||||
|
||||
union DN_CHCR
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t direction : 1;
|
||||
uint32_t increment : 1;
|
||||
uint32_t : 6;
|
||||
uint32_t bit_8 : 1;
|
||||
uint32_t transfer_mode : 2;
|
||||
uint32_t : 5;
|
||||
uint32_t chop_dma : 3;
|
||||
uint32_t : 1;
|
||||
uint32_t chop_cpu : 3;
|
||||
uint32_t : 1;
|
||||
uint32_t running : 1;
|
||||
uint32_t : 3;
|
||||
uint32_t trigger : 1;
|
||||
uint32_t : 3;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint32_t direction : 1;
|
||||
uint32_t increment : 1;
|
||||
uint32_t : 6;
|
||||
uint32_t bit_8 : 1;
|
||||
uint32_t transfer_mode : 2;
|
||||
uint32_t : 5;
|
||||
uint32_t chop_dma : 3;
|
||||
uint32_t : 1;
|
||||
uint32_t chop_cpu : 3;
|
||||
uint32_t : 1;
|
||||
uint32_t running : 1;
|
||||
uint32_t : 3;
|
||||
uint32_t trigger : 1;
|
||||
uint32_t : 3;
|
||||
};
|
||||
};
|
||||
|
||||
union DN_BCR
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t size : 16;
|
||||
uint32_t count : 16;
|
||||
};
|
||||
};
|
||||
|
||||
struct DMAChannels
|
||||
{
|
||||
uint32_t madr;
|
||||
uint32_t bcr;
|
||||
DN_BCR bcr;
|
||||
DN_CHCR chcr;
|
||||
uint32_t tadr;
|
||||
} channels[13];
|
||||
|
||||
union DMATag
|
||||
{
|
||||
uint64_t value;
|
||||
struct
|
||||
{
|
||||
uint64_t start_addr : 24;
|
||||
uint64_t : 6;
|
||||
uint64_t irq : 1;
|
||||
uint64_t end : 1;
|
||||
uint64_t size : 24;
|
||||
};
|
||||
};
|
||||
|
||||
void IopDma::WriteDPCR(uint32_t data)
|
||||
{
|
||||
dpcr = data;
|
||||
|
@ -49,6 +90,191 @@ void IopDma::WriteDPCR2(uint32_t data)
|
|||
printf("[emu/IopDma]: Writing 0x%08x to DPCR2\n", data);
|
||||
}
|
||||
|
||||
bool sif1_transfer_running = false;
|
||||
|
||||
DMATag sif1_tag;
|
||||
|
||||
void HandleSIF1Transfer()
|
||||
{
|
||||
auto& c = channels[10];
|
||||
|
||||
// Handle any leftovers that may believe we're still transfering
|
||||
if (!sif1_transfer_running)
|
||||
return;
|
||||
|
||||
printf("[emu/IopDma]: Transfer of mode %d, %d blocks\n", c.chcr.transfer_mode, c.bcr.count);
|
||||
|
||||
if (c.bcr.count)
|
||||
{
|
||||
while (c.bcr.count)
|
||||
{
|
||||
if (SIF::FIFO1_size())
|
||||
{
|
||||
auto data = SIF::ReadAndPopSIF1();
|
||||
|
||||
Bus::iop_write<uint32_t>(c.madr, data);
|
||||
c.madr += 4;
|
||||
c.bcr.count--;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (sif1_tag.irq && !c.bcr.count)
|
||||
{
|
||||
dicr2.flags |= (1 << 3);
|
||||
|
||||
if (dicr2.flags & dicr2.mask)
|
||||
Bus::TriggerIOPInterrupt(3);
|
||||
}
|
||||
|
||||
if (sif1_tag.end)
|
||||
{
|
||||
sif1_transfer_running = false;
|
||||
c.chcr.running = 0;
|
||||
|
||||
dicr2.flags |= (1 << 3);
|
||||
|
||||
if (dicr2.flags & dicr2.mask)
|
||||
Bus::TriggerIOPInterrupt(3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[emu/IopDma]: Sif1 FIFO size is %ld\n", SIF::FIFO1_size());
|
||||
if (SIF::FIFO1_size() >= 4)
|
||||
{
|
||||
uint32_t data[2];
|
||||
for (int i = 0; i < 2; i++)
|
||||
data[i] = SIF::ReadAndPopSIF1();
|
||||
|
||||
SIF::ReadAndPopSIF1();
|
||||
SIF::ReadAndPopSIF1();
|
||||
|
||||
sif1_tag.value = *(uint64_t*)data;
|
||||
|
||||
printf("[emu/IopDma]: Found SIF1 DMATag 0x%08lx: Start address 0x%08x, size %d bytes\n", sif1_tag.value, sif1_tag.start_addr, sif1_tag.size);
|
||||
|
||||
c.madr = sif1_tag.start_addr;
|
||||
c.bcr.count = (sif1_tag.size + 3) & 0xfffffffc;
|
||||
}
|
||||
}
|
||||
|
||||
if (sif1_transfer_running)
|
||||
{
|
||||
Scheduler::Event evt;
|
||||
evt.name = "SIF1Transfer";
|
||||
evt.func = HandleSIF1Transfer;
|
||||
evt.cycles_from_now = 8*c.bcr.count;
|
||||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool sif0_transfer_running = false;
|
||||
|
||||
DMATag sif0_tag;
|
||||
|
||||
void HandleSIF0Transfer()
|
||||
{
|
||||
auto& c = channels[9];
|
||||
|
||||
// Handle any leftovers that may believe we're still transfering
|
||||
if (!sif0_transfer_running)
|
||||
return;
|
||||
|
||||
printf("[emu/IopDma]: Transfer of mode %d, %d blocks\n", c.chcr.transfer_mode, c.bcr.count);
|
||||
|
||||
if (c.bcr.count)
|
||||
{
|
||||
while (c.bcr.count)
|
||||
{
|
||||
uint32_t data = Bus::iop_read<uint32_t>(c.madr);
|
||||
printf("[emu/IopDma]: Adding 0x%08x to SIF0 fifo\n", data);
|
||||
SIF::WriteFIFO0(data);
|
||||
c.madr += 4;
|
||||
c.bcr.count--;
|
||||
}
|
||||
|
||||
|
||||
if (sif0_tag.irq && !c.bcr.count)
|
||||
{
|
||||
dicr2.flags |= (1 << 2);
|
||||
|
||||
if (dicr2.flags & dicr2.mask)
|
||||
Bus::TriggerIOPInterrupt(3);
|
||||
}
|
||||
|
||||
if (sif1_tag.end)
|
||||
{
|
||||
sif0_transfer_running = false;
|
||||
c.chcr.running = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sif0_tag.value = Bus::iop_read<uint64_t>(c.tadr);
|
||||
c.madr = sif0_tag.start_addr;
|
||||
|
||||
c.bcr.count = (sif0_tag.size + 3) & 0xfffffffc;
|
||||
c.tadr += 8;
|
||||
|
||||
if (c.chcr.bit_8)
|
||||
{
|
||||
SIF::WriteFIFO0(Bus::iop_read<uint32_t>(c.tadr));
|
||||
SIF::WriteFIFO0(Bus::iop_read<uint32_t>(c.tadr + 4));
|
||||
|
||||
c.tadr += 8;
|
||||
}
|
||||
|
||||
printf("[emu/IopDma]: Found SIF0 DMATag 0x%08lx: Start address 0x%08x, size %d bytes\n", sif0_tag.value, sif0_tag.start_addr, sif0_tag.size);
|
||||
}
|
||||
|
||||
if (sif0_transfer_running)
|
||||
{
|
||||
Scheduler::Event evt;
|
||||
evt.name = "SIF0Transfer";
|
||||
evt.func = HandleSIF0Transfer;
|
||||
evt.cycles_from_now = 8*c.bcr.count;
|
||||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HandleRunningChannel(int chan, DMAChannels& c)
|
||||
{
|
||||
if (chan == 10)
|
||||
{
|
||||
sif1_transfer_running = true;
|
||||
|
||||
Scheduler::Event evt;
|
||||
evt.name = "SIF1Transfer";
|
||||
evt.func = HandleSIF1Transfer;
|
||||
evt.cycles_from_now = 8;
|
||||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
else if (chan == 9)
|
||||
{
|
||||
sif0_transfer_running = true;
|
||||
|
||||
Scheduler::Event evt;
|
||||
evt.name = "SIF0Transfer";
|
||||
evt.func = HandleSIF0Transfer;
|
||||
evt.cycles_from_now = 8;
|
||||
|
||||
Scheduler::ScheduleEvent(evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void IopDma::WriteDMACEN(uint32_t data)
|
||||
{
|
||||
dmacen = data & 1;
|
||||
|
@ -58,9 +284,10 @@ void IopDma::WriteDMACEN(uint32_t data)
|
|||
for (int i = 0; i < 13; i++)
|
||||
{
|
||||
auto& c = channels[i];
|
||||
|
||||
if (c.chcr.running)
|
||||
{
|
||||
printf("Starting transfer on channel %d\n", i);
|
||||
HandleRunningChannel(i, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +300,11 @@ void IopDma::WriteDICR(uint32_t data)
|
|||
|
||||
void IopDma::WriteDICR2(uint32_t data)
|
||||
{
|
||||
dicr2 = data;
|
||||
auto& irq = dicr2;
|
||||
auto flags = irq.flags;
|
||||
|
||||
irq.value = data;
|
||||
irq.flags = flags & ~((data >> 24) & 0x7f);
|
||||
}
|
||||
|
||||
const char* REGS[] =
|
||||
|
@ -92,26 +323,29 @@ void IopDma::WriteChannel(uint32_t addr, uint32_t data)
|
|||
|
||||
channel -= 0x8;
|
||||
|
||||
printf("[emu/IopDma]: Writing 0x%08x to %s of channel %d\n", data, REGS[reg], channel);
|
||||
printf("[emu/IopDma]: Writing 0x%08x to %s of channel %d (0x%08x)\n", data, REGS[reg], channel, addr);
|
||||
|
||||
switch (addr)
|
||||
switch (reg)
|
||||
{
|
||||
case 0x0:
|
||||
channels[channel].madr = data;
|
||||
return;
|
||||
break;
|
||||
case 0x1:
|
||||
channels[channel].bcr = data;
|
||||
return;
|
||||
channels[channel].bcr.value = data;
|
||||
break;
|
||||
case 0x2:
|
||||
channels[channel].chcr.value = data;
|
||||
return;
|
||||
break;
|
||||
case 0x3:
|
||||
channels[channel].tadr = data;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (channels[channel].chcr.running)
|
||||
if (channels[channel].chcr.running && dmacen)
|
||||
{
|
||||
printf("[emu/IopDma]: Starting transfer on channel %d\n", channel);
|
||||
HandleRunningChannel(channel, channels[channel]);
|
||||
}
|
||||
}
|
||||
|
||||
void IopDma::WriteNewChannel(uint32_t addr, uint32_t data)
|
||||
|
@ -120,28 +354,52 @@ void IopDma::WriteNewChannel(uint32_t addr, uint32_t data)
|
|||
int reg = addr & 0xf;
|
||||
reg /= 4;
|
||||
|
||||
channel += 8;
|
||||
channel += 7;
|
||||
|
||||
printf("[emu/IopDma]: Writing 0x%08x to %s of channel %d\n", data, REGS[reg], channel);
|
||||
printf("[emu/IopDma]: Writing 0x%08x to %s of channel %d (0x%08x)\n", data, REGS[reg], channel, addr);
|
||||
|
||||
switch (addr)
|
||||
switch (reg)
|
||||
{
|
||||
case 0x0:
|
||||
channels[channel].madr = data;
|
||||
return;
|
||||
break;
|
||||
case 0x1:
|
||||
channels[channel].bcr = data;
|
||||
return;
|
||||
channels[channel].bcr.value = data;
|
||||
break;
|
||||
case 0x2:
|
||||
channels[channel].chcr.value = data;
|
||||
return;
|
||||
break;
|
||||
case 0x3:
|
||||
channels[channel].tadr = data;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (channels[channel].chcr.running)
|
||||
if (channels[channel].chcr.running && dmacen)
|
||||
{
|
||||
printf("[emu/IopDma]: Starting transfer on channel %d\n", channel);
|
||||
HandleRunningChannel(channel, channels[channel]);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t IopDma::ReadNewChannel(uint32_t addr)
|
||||
{
|
||||
int channel = (addr >> 4) & 0xf;
|
||||
int reg = addr & 0xf;
|
||||
reg /= 4;
|
||||
|
||||
channel += 7;
|
||||
|
||||
switch (reg)
|
||||
{
|
||||
case 0x0:
|
||||
return channels[channel].madr;
|
||||
case 0x1:
|
||||
return channels[channel].bcr.value;
|
||||
case 0x2:
|
||||
return channels[channel].chcr.value;
|
||||
case 0x3:
|
||||
return channels[channel].tadr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t IopDma::ReadDMACEN()
|
||||
|
@ -151,7 +409,7 @@ uint32_t IopDma::ReadDMACEN()
|
|||
|
||||
uint32_t IopDma::ReadDICR2()
|
||||
{
|
||||
return dicr2;
|
||||
return dicr2.value;
|
||||
}
|
||||
|
||||
uint32_t IopDma::ReadDICR()
|
||||
|
|
|
@ -14,6 +14,8 @@ void WriteDICR2(uint32_t data);
|
|||
void WriteChannel(uint32_t addr, uint32_t data);
|
||||
void WriteNewChannel(uint32_t addr, uint32_t data);
|
||||
|
||||
uint32_t ReadNewChannel(uint32_t addr);
|
||||
|
||||
uint32_t ReadDMACEN();
|
||||
uint32_t ReadDICR2();
|
||||
uint32_t ReadDICR();
|
||||
|
|
|
@ -495,7 +495,7 @@ void CPU::op_sw()
|
|||
}
|
||||
|
||||
if (!isCacheIsolated())
|
||||
Bus::iop_write(addr, regs[rt]);
|
||||
Bus::iop_write<uint32_t>(addr, regs[rt]);
|
||||
}
|
||||
|
||||
void CPU::op_swr()
|
||||
|
|
14
src/emu/cpu/iop/timers.cpp
Normal file
14
src/emu/cpu/iop/timers.cpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include "timers.h"
|
||||
|
||||
union TimerMode
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
void Timers::WriteTimerMode(int timer, uint32_t data)
|
||||
{
|
||||
}
|
10
src/emu/cpu/iop/timers.h
Normal file
10
src/emu/cpu/iop/timers.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Timers
|
||||
{
|
||||
|
||||
void WriteTimerMode(int timer, uint32_t data);
|
||||
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
#include "cdvd.h"
|
||||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <emu/dev/cdvd.h>
|
||||
|
||||
uint8_t N_status = (1 << 6);
|
||||
|
||||
uint8_t CDVD::ReadNStatus()
|
||||
{
|
||||
return N_status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -5,4 +8,4 @@
|
|||
namespace CDVD
|
||||
{
|
||||
uint8_t ReadNStatus();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
#include "sif.h"
|
||||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <emu/dev/sif.h>
|
||||
|
||||
#include <queue>
|
||||
|
||||
uint32_t sif_ctrl;
|
||||
uint32_t bd6;
|
||||
|
@ -7,6 +12,8 @@ uint32_t smcom;
|
|||
uint32_t msflg;
|
||||
uint32_t smflg;
|
||||
|
||||
std::queue<uint32_t> fifo0, fifo1;
|
||||
|
||||
void SIF::WriteMSCOM_EE(uint32_t data)
|
||||
{
|
||||
mscom = data;
|
||||
|
@ -61,6 +68,11 @@ void SIF::WriteSMFLG_IOP(uint32_t data)
|
|||
smflg = data;
|
||||
}
|
||||
|
||||
void SIF::WriteMSFLG_IOP(uint32_t data)
|
||||
{
|
||||
msflg &= ~data;
|
||||
}
|
||||
|
||||
uint32_t SIF::ReadMSCOM_EE()
|
||||
{
|
||||
return mscom;
|
||||
|
@ -88,5 +100,28 @@ uint32_t SIF::ReadCTRL()
|
|||
|
||||
size_t SIF::FIFO0_size()
|
||||
{
|
||||
return 0;
|
||||
return fifo0.size();
|
||||
}
|
||||
|
||||
size_t SIF::FIFO1_size()
|
||||
{
|
||||
return fifo1.size();
|
||||
}
|
||||
|
||||
void SIF::WriteFIFO0(uint32_t data)
|
||||
{
|
||||
fifo0.push(data);
|
||||
}
|
||||
|
||||
void SIF::WriteFIFO1(uint32_t data)
|
||||
{
|
||||
fifo1.push(data);
|
||||
}
|
||||
|
||||
uint32_t SIF::ReadAndPopSIF1()
|
||||
{
|
||||
uint32_t data = fifo1.front();
|
||||
fifo1.pop();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <util/uint128.h>
|
||||
|
@ -14,6 +17,7 @@ void WriteBD6_EE(uint32_t data);
|
|||
void WriteCTRL_IOP(uint32_t data);
|
||||
void WriteSMCOM_IOP(uint32_t data);
|
||||
void WriteSMFLG_IOP(uint32_t data);
|
||||
void WriteMSFLG_IOP(uint32_t data);
|
||||
|
||||
uint32_t ReadMSCOM_EE();
|
||||
uint32_t ReadSMCOM();
|
||||
|
@ -22,5 +26,11 @@ uint32_t ReadSMFLG();
|
|||
uint32_t ReadCTRL();
|
||||
|
||||
size_t FIFO0_size();
|
||||
size_t FIFO1_size();
|
||||
|
||||
}
|
||||
void WriteFIFO0(uint32_t data);
|
||||
void WriteFIFO1(uint32_t data);
|
||||
|
||||
uint32_t ReadAndPopSIF1();
|
||||
|
||||
} // namespace SIF
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include "gif.hpp"
|
||||
#include <emu/gpu/gif.hpp>
|
||||
|
||||
#include <emu/sched/scheduler.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <queue>
|
||||
#include <emu/sched/scheduler.h>
|
||||
|
||||
namespace GIF
|
||||
{
|
||||
|
@ -76,8 +77,10 @@ void ProcessGIFData()
|
|||
{
|
||||
tag.value = fifo.front().u128;
|
||||
data_count = tag.nloop;
|
||||
printf("[emu/GIF]: Received GIFTag: nloop: 0%04x, eop: %d, prim_en: %d, prim_data: 0x%04x, fmt: %d, nregs: %d, regs: 0x%08lx\n",
|
||||
tag.nloop, tag.eop, tag.prim_en, tag.prim_data, tag.fmt, tag.nregs, tag.reg);
|
||||
printf("[emu/GIF]: Received GIFTag: nloop: 0%04x, eop: %d, prim_en: %d, prim_data: 0x%04x, fmt: %d, nregs: %d, regs: 0x%08lx\n",
|
||||
tag.nloop, tag.eop,
|
||||
tag.prim_en, tag.prim_data,
|
||||
tag.fmt, tag.nregs, tag.reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -124,12 +127,13 @@ uint32_t ReadStat()
|
|||
|
||||
void WriteFIFO(uint128_t data)
|
||||
{
|
||||
printf("[emu/GIF]: Adding 0x%lx%016lx to GIF FIFO\n", data.u64[1], data.u64[0]);
|
||||
printf("[emu/GIF]: Adding 0x%lx%016lx to GIF FIFO\n",
|
||||
data.u64[1], data.u64[0]);
|
||||
if (fifo.size() < 16)
|
||||
{
|
||||
fifo.push(data);
|
||||
}
|
||||
|
||||
|
||||
if (!event_scheduled)
|
||||
{
|
||||
Scheduler::Event event;
|
||||
|
@ -142,4 +146,5 @@ void WriteFIFO(uint128_t data)
|
|||
Scheduler::ScheduleEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GIF
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <util/uint128.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace GIF
|
||||
{
|
||||
|
||||
|
@ -13,4 +17,4 @@ uint32_t ReadStat();
|
|||
|
||||
void WriteFIFO(uint128_t data);
|
||||
|
||||
}
|
||||
} // namespace GIF
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "gs.h"
|
||||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <emu/gpu/gs.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
@ -51,4 +54,4 @@ void WriteGSCSR(uint64_t data)
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace GS
|
||||
|
|
|
@ -16,4 +16,4 @@ inline void WriteGSSYNCH1(uint64_t data) {}
|
|||
inline void WriteGSSYNCH2(uint64_t data) {}
|
||||
inline void WriteGSSYNCV(uint64_t data) {}
|
||||
|
||||
}
|
||||
} // namespace GS
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include "Bus.h"
|
||||
#include <emu/memory/Bus.h>
|
||||
|
||||
#include <emu/cpu/ee/vu.h>
|
||||
#include <emu/cpu/ee/vif.h>
|
||||
#include <emu/dev/sif.h>
|
||||
#include <emu/gpu/gs.h>
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
|
||||
#include <emu/gpu/gif.hpp>
|
||||
#include <emu/gpu/gs.h>
|
||||
#include <emu/cpu/ee/dmac.hpp>
|
||||
#include <emu/cpu/ee/vu.h>
|
||||
#include <emu/cpu/ee/vif.h>
|
||||
#include <emu/dev/sif.h>
|
||||
|
||||
uint8_t* BiosRom;
|
||||
uint8_t spr[0x4000];
|
||||
|
@ -27,7 +30,7 @@ uint32_t Bus::I_MASK = 0, Bus::I_STAT = 0, Bus::I_CTRL = 0;
|
|||
|
||||
uint32_t Translate(uint32_t addr)
|
||||
{
|
||||
constexpr uint32_t KUSEG_MASKS[8] =
|
||||
constexpr uint32_t KUSEG_MASKS[8] =
|
||||
{
|
||||
/* KUSEG: Don't touch the address, it's fine */
|
||||
0xffffffff, 0xfffffff, 0xfffffff, 0xffffffff,
|
||||
|
@ -66,7 +69,7 @@ void Bus::Dump()
|
|||
|
||||
for (int i = 0; i < 0x4000; i++)
|
||||
{
|
||||
dump << (char)spr[i];
|
||||
dump << static_cast<char>(spr[i]);
|
||||
}
|
||||
|
||||
dump.close();
|
||||
|
@ -75,7 +78,7 @@ void Bus::Dump()
|
|||
|
||||
for (int i = 0; i < 0x2000000; i++)
|
||||
{
|
||||
dump << (char)ram[i];
|
||||
dump << static_cast<char>(ram[i]);
|
||||
}
|
||||
|
||||
dump.close();
|
||||
|
@ -84,7 +87,7 @@ void Bus::Dump()
|
|||
|
||||
for (int i = 0; i < 0x200000; i++)
|
||||
{
|
||||
dump << (char)iop_ram[i];
|
||||
dump << static_cast<char>(iop_ram[i]);
|
||||
}
|
||||
|
||||
dump.close();
|
||||
|
@ -95,8 +98,8 @@ uint128_t Bus::Read128(uint32_t addr)
|
|||
addr = Translate(addr);
|
||||
|
||||
if (addr < 0x2000000)
|
||||
return {*(__uint128_t*)&ram[addr]};
|
||||
|
||||
return {*reinterpret_cast<__uint128_t*>(&ram[addr])};
|
||||
|
||||
printf("Read128 from unknown address 0x%08x\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -106,12 +109,12 @@ uint64_t Bus::Read64(uint32_t addr)
|
|||
addr = Translate(addr);
|
||||
|
||||
if (addr >= 0x1fc00000 && addr < 0x20000000)
|
||||
return *(uint64_t*)&BiosRom[addr - 0x1fc00000];
|
||||
return *reinterpret_cast<uint64_t*>(&BiosRom[addr - 0x1fc00000]);
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
return *(uint64_t*)&spr[addr - 0x70000000];
|
||||
return *reinterpret_cast<uint64_t*>(&spr[addr - 0x70000000]);
|
||||
if (addr < 0x2000000)
|
||||
return *(uint64_t*)&ram[addr];
|
||||
|
||||
return *reinterpret_cast<uint64_t*>(&ram[addr]);
|
||||
|
||||
printf("Read64 from unknown address 0x%08x\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -121,13 +124,13 @@ uint32_t Bus::Read32(uint32_t addr)
|
|||
addr = Translate(addr);
|
||||
|
||||
if (addr >= 0x1fc00000 && addr < 0x20000000)
|
||||
return *(uint32_t*)&BiosRom[addr - 0x1fc00000];
|
||||
return *reinterpret_cast<uint32_t*>(&BiosRom[addr - 0x1fc00000]);
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
return *(uint32_t*)&spr[addr - 0x70000000];
|
||||
return *reinterpret_cast<uint32_t*>(&spr[addr - 0x70000000]);
|
||||
if (addr < 0x2000000)
|
||||
return *(uint32_t*)&ram[addr];
|
||||
return *reinterpret_cast<uint32_t*>(&ram[addr]);
|
||||
if (addr >= 0x1C000000 && addr < 0x1C200000)
|
||||
return *(uint32_t*)&iop_ram[addr - 0x1C000000];
|
||||
return *reinterpret_cast<uint32_t*>(&iop_ram[addr - 0x1C000000]);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
|
@ -171,6 +174,10 @@ uint32_t Bus::Read32(uint32_t addr)
|
|||
case 0x1000C000:
|
||||
case 0x1000C020:
|
||||
return DMAC::ReadSIF0Channel(addr);
|
||||
case 0x1000C400:
|
||||
case 0x1000C420:
|
||||
case 0x1000C430:
|
||||
return DMAC::ReadSIF1Channel(addr);
|
||||
case 0x1000E000:
|
||||
return DMAC::ReadDCTRL();
|
||||
case 0x1000E010:
|
||||
|
@ -185,10 +192,12 @@ uint32_t Bus::Read32(uint32_t addr)
|
|||
return SIF::ReadMSFLG();
|
||||
case 0x1000F230:
|
||||
return SIF::ReadSMFLG();
|
||||
case 0x1000F520:
|
||||
return DMAC::ReadDENABLE();
|
||||
case 0x10002010:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
printf("Read32 from unknown address 0x%08x\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -196,14 +205,14 @@ uint32_t Bus::Read32(uint32_t addr)
|
|||
uint16_t Bus::Read16(uint32_t addr)
|
||||
{
|
||||
addr = Translate(addr);
|
||||
|
||||
|
||||
if (addr >= 0x1fc00000 && addr < 0x20000000)
|
||||
return *(uint16_t*)&BiosRom[addr - 0x1fc00000];
|
||||
return *reinterpret_cast<uint16_t*>(&BiosRom[addr - 0x1fc00000]);
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
return *(uint16_t*)&spr[addr - 0x70000000];
|
||||
return *reinterpret_cast<uint16_t*>(&spr[addr - 0x70000000]);
|
||||
if (addr < 0x2000000)
|
||||
return *(uint16_t*)&ram[addr];
|
||||
|
||||
return *reinterpret_cast<uint16_t*>(&ram[addr]);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x1f803800:
|
||||
|
@ -218,6 +227,11 @@ uint8_t Bus::Read8(uint32_t addr)
|
|||
{
|
||||
addr = Translate(addr);
|
||||
|
||||
if (addr == 0x1e104)
|
||||
{
|
||||
printf("Reading from transfers_queued\n");
|
||||
}
|
||||
|
||||
|
||||
if (addr >= 0x1fc00000 && addr < 0x20000000)
|
||||
return BiosRom[addr - 0x1fc00000];
|
||||
|
@ -225,31 +239,31 @@ uint8_t Bus::Read8(uint32_t addr)
|
|||
return spr[addr - 0x70000000];
|
||||
if (addr < 0x2000000)
|
||||
return ram[addr];
|
||||
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x1f803204:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
printf("Read from unknown address 0x%08x\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void Bus::Write128(uint32_t addr, uint128_t data)
|
||||
{
|
||||
addr = Translate(addr);
|
||||
|
||||
EmotionEngine::MarkDirty(addr, sizeof(data));
|
||||
|
||||
addr = Translate(addr);
|
||||
|
||||
if (addr < 0x2000000)
|
||||
{
|
||||
*(__uint128_t*)&ram[addr] = data.u128;
|
||||
*reinterpret_cast<__uint128_t*>(&ram[addr]) = data.u128;
|
||||
return;
|
||||
}
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
{
|
||||
*(__uint128_t*)&spr[addr - 0x70000000] = data.u128;
|
||||
*reinterpret_cast<__uint128_t*>(&spr[addr - 0x70000000]) = data.u128;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -284,24 +298,25 @@ void Bus::Write128(uint32_t addr, uint128_t data)
|
|||
return;
|
||||
}
|
||||
|
||||
printf("Write128 0x%lx%016lx to unknown address 0x%08x\n", data.u64[1], data.u64[0], addr);
|
||||
printf("Write128 0x%lx%016lx to unknown address 0x%08x\n",
|
||||
data.u64[1], data.u64[0], addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void Bus::Write64(uint32_t addr, uint64_t data)
|
||||
{
|
||||
addr = Translate(addr);
|
||||
|
||||
EmotionEngine::MarkDirty(addr, sizeof(data));
|
||||
|
||||
addr = Translate(addr);
|
||||
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
{
|
||||
*(uint64_t*)&spr[addr - 0x70000000] = data;
|
||||
*reinterpret_cast<uint64_t*>(&spr[addr - 0x70000000]) = data;
|
||||
return;
|
||||
}
|
||||
if (addr < 0x2000000)
|
||||
{
|
||||
*(uint64_t*)&ram[addr] = data;
|
||||
*reinterpret_cast<uint64_t*>(&ram[addr]) = data;
|
||||
return;
|
||||
}
|
||||
if (addr >= 0x11008000 && addr < 0x1100C000)
|
||||
|
@ -341,29 +356,34 @@ void Bus::Write64(uint32_t addr, uint64_t data)
|
|||
|
||||
void Bus::Write32(uint32_t addr, uint32_t data)
|
||||
{
|
||||
EmotionEngine::MarkDirty(addr, sizeof(data));
|
||||
|
||||
if (addr == 0x8001e140)
|
||||
{
|
||||
printf("Writing 0x%08x to GIFTAG stuff\n", data);
|
||||
}
|
||||
|
||||
addr = Translate(addr);
|
||||
|
||||
EmotionEngine::MarkDirty(addr, sizeof(data));
|
||||
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
{
|
||||
*(uint32_t*)&spr[addr - 0x70000000] = data;
|
||||
*reinterpret_cast<uint32_t*>(&spr[addr - 0x70000000]) = data;
|
||||
return;
|
||||
}
|
||||
if (addr < 0x2000000)
|
||||
{
|
||||
*(uint32_t*)&ram[addr] = data;
|
||||
*reinterpret_cast<uint32_t*>(&ram[addr]) = data;
|
||||
return;
|
||||
}
|
||||
if (addr >= 0x1C000000 && addr < 0x1C200000)
|
||||
{
|
||||
*(uint32_t*)&iop_ram[addr-0x1C000000] = data;
|
||||
*reinterpret_cast<uint32_t*>(&iop_ram[addr-0x1C000000]) = data;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x1000f100: // Some weird RDRAM stuff
|
||||
case 0x1000f100: // Some weird RDRAM stuff
|
||||
case 0x1000f120:
|
||||
case 0x1000f140:
|
||||
case 0x1000f150:
|
||||
|
@ -382,7 +402,7 @@ void Bus::Write32(uint32_t addr, uint32_t data)
|
|||
case 0x1000f010:
|
||||
INTC_MASK = data;
|
||||
return;
|
||||
case 0x1000f500: // EE TLB enable?
|
||||
case 0x1000f500: // EE TLB enable?
|
||||
return;
|
||||
case 0x1000f430:
|
||||
{
|
||||
|
@ -391,7 +411,7 @@ void Bus::Write32(uint32_t addr, uint32_t data)
|
|||
|
||||
if (SA == 0x21 && SBC == 0x1 && ((MCH_DRD >> 7) & 1) == 0)
|
||||
rdram_sdevid = 0;
|
||||
|
||||
|
||||
MCH_RICM = data & ~0x80000000;
|
||||
return;
|
||||
}
|
||||
|
@ -547,6 +567,9 @@ void Bus::Write32(uint32_t addr, uint32_t data)
|
|||
case 0x1000F260:
|
||||
SIF::WriteBD6_EE(data);
|
||||
return;
|
||||
case 0x1000F590:
|
||||
DMAC::WriteDENABLE(data);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Write32 0x%08x to unknown address 0x%08x\n", data, addr);
|
||||
|
@ -555,18 +578,18 @@ void Bus::Write32(uint32_t addr, uint32_t data)
|
|||
|
||||
void Bus::Write16(uint32_t addr, uint16_t data)
|
||||
{
|
||||
EmotionEngine::MarkDirty(addr, sizeof(data));
|
||||
|
||||
addr = Translate(addr);
|
||||
|
||||
EmotionEngine::MarkDirty(addr, sizeof(data));
|
||||
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
{
|
||||
*(uint16_t*)&spr[addr - 0x70000000] = data;
|
||||
*reinterpret_cast<uint16_t*>(&spr[addr - 0x70000000]) = data;
|
||||
return;
|
||||
}
|
||||
if (addr < 0x2000000)
|
||||
{
|
||||
*(uint16_t*)&ram[addr] = data;
|
||||
*reinterpret_cast<uint16_t*>(&ram[addr]) = data;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -579,10 +602,15 @@ void Bus::Write16(uint32_t addr, uint16_t data)
|
|||
|
||||
void Bus::Write8(uint32_t addr, uint8_t data)
|
||||
{
|
||||
addr = Translate(addr);
|
||||
|
||||
EmotionEngine::MarkDirty(addr, sizeof(data));
|
||||
|
||||
if (addr == 0x8001e104)
|
||||
{
|
||||
printf("Writing 0x%02x to transfers_queued\n", data);
|
||||
}
|
||||
|
||||
addr = Translate(addr);
|
||||
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
{
|
||||
spr[addr - 0x70000000] = data;
|
||||
|
@ -597,7 +625,7 @@ void Bus::Write8(uint32_t addr, uint8_t data)
|
|||
switch (addr)
|
||||
{
|
||||
case 0x1000f180:
|
||||
console << (char)data;
|
||||
console << static_cast<char>(data);
|
||||
console.flush();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <util/uint128.h>
|
||||
|
||||
#include <emu/cpu/iop/dma.h>
|
||||
#include <emu/dev/cdvd.h>
|
||||
#include <emu/dev/sif.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
uint32_t Translate(uint32_t addr);
|
||||
extern uint8_t* BiosRom;
|
||||
extern uint8_t* iop_ram;
|
||||
|
@ -41,9 +41,9 @@ T iop_read(uint32_t addr)
|
|||
addr = Translate(addr);
|
||||
|
||||
if (addr >= 0x1fc00000 && addr < 0x20000000)
|
||||
return *(T*)&BiosRom[addr - 0x1fc00000];
|
||||
return *reinterpret_cast<T*>(&BiosRom[addr - 0x1fc00000]);
|
||||
if (addr < 0x200000)
|
||||
return *(T*)&iop_ram[addr];
|
||||
return *reinterpret_cast<T*>(&iop_ram[addr]);
|
||||
if (addr >= 0x1E000000 && addr < 0x1F000000)
|
||||
return 0;
|
||||
|
||||
|
@ -72,6 +72,8 @@ T iop_read(uint32_t addr)
|
|||
return IopDma::ReadDPCR();
|
||||
case 0x1f8010f4:
|
||||
return IopDma::ReadDICR();
|
||||
case 0x1f801070:
|
||||
return I_STAT;
|
||||
case 0x1f801078:
|
||||
return I_CTRL;
|
||||
case 0x1f801570:
|
||||
|
@ -88,6 +90,14 @@ T iop_read(uint32_t addr)
|
|||
case 0x1F801490 ... 0x1F801498:
|
||||
case 0x1F8014A0 ... 0x1F8014A8:
|
||||
return 0;
|
||||
|
||||
case 0x1f801500 ... 0x1f80150C:
|
||||
case 0x1f801510 ... 0x1f80151C:
|
||||
case 0x1f801520 ... 0x1f80152C:
|
||||
case 0x1f801530 ... 0x1f80153C:
|
||||
case 0x1f801540 ... 0x1f80154C:
|
||||
case 0x1f801550 ... 0x1f80155C:
|
||||
return IopDma::ReadNewChannel(addr);
|
||||
}
|
||||
|
||||
printf("[emu/IopBus]: Read from unknown addr 0x%08x\n", addr);
|
||||
|
@ -98,10 +108,10 @@ template<typename T>
|
|||
void iop_write(uint32_t addr, T data)
|
||||
{
|
||||
addr = Translate(addr);
|
||||
|
||||
|
||||
if (addr < 0x200000)
|
||||
{
|
||||
*(T*)&iop_ram[addr] = data;
|
||||
*reinterpret_cast<T*>(&iop_ram[addr]) = data;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -110,6 +120,9 @@ void iop_write(uint32_t addr, T data)
|
|||
case 0x1d000010:
|
||||
SIF::WriteSMCOM_IOP(data);
|
||||
return;
|
||||
case 0x1d000020:
|
||||
SIF::WriteMSFLG_IOP(data);
|
||||
return;
|
||||
case 0x1d000030:
|
||||
SIF::WriteSMFLG_IOP(data);
|
||||
return;
|
||||
|
@ -147,6 +160,9 @@ void iop_write(uint32_t addr, T data)
|
|||
case 0x1ffe0144:
|
||||
printf("[emu/IOP]: Scratchpad start 0x%08x\n", data);
|
||||
return;
|
||||
case 0x1f801070:
|
||||
I_STAT &= data;
|
||||
return;
|
||||
case 0x1f801074:
|
||||
I_MASK = data;
|
||||
return;
|
||||
|
@ -199,4 +215,9 @@ void iop_write(uint32_t addr, T data)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
inline void TriggerIOPInterrupt(int i_num)
|
||||
{
|
||||
I_STAT |= (1 << i_num);
|
||||
}
|
||||
|
||||
} // namespace Bus
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
#include "scheduler.h"
|
||||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <emu/sched/scheduler.h>
|
||||
|
||||
#include <emu/cpu/iop/cpu.h>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <cinttypes>
|
||||
#include <emu/cpu/iop/cpu.h>
|
||||
|
||||
namespace Scheduler
|
||||
{
|
||||
|
@ -15,10 +20,6 @@ std::vector<Event> event_queue;
|
|||
void InitScheduler()
|
||||
{
|
||||
std::make_heap(event_queue.begin(), event_queue.end());
|
||||
// Event infinite_event;
|
||||
// infinite_event.cycles_from_now = std::numeric_limits<uintmax_t>::max() - global_cycles;
|
||||
// infinite_event.name = "Infinite Event (Unreachable)";
|
||||
// ScheduleEvent(infinite_event);
|
||||
}
|
||||
|
||||
bool CompareEvents(const Event& a, const Event& b)
|
||||
|
@ -29,7 +30,7 @@ bool CompareEvents(const Event& a, const Event& b)
|
|||
void ScheduleEvent(Event event)
|
||||
{
|
||||
event.cycles_from_now += global_cycles;
|
||||
if (event.cycles_from_now < global_cycles) // Overflow detected
|
||||
if (event.cycles_from_now < global_cycles) // Overflow detected
|
||||
{
|
||||
printf("[emu/Sched]: Overflow found\n");
|
||||
for (auto& e : event_queue)
|
||||
|
@ -60,9 +61,6 @@ void CheckScheduler(int cycles)
|
|||
event_queue.pop_back();
|
||||
e.func();
|
||||
}
|
||||
|
||||
// if (!event_queue.empty())
|
||||
// printf("[emu/Sched]: Next event is in %d cycles\n", event_queue.front().cycles_from_now - global_cycles);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Scheduler
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -15,7 +18,7 @@ struct Event
|
|||
EventFunc func;
|
||||
std::string name;
|
||||
|
||||
bool operator<(Event& rhs)
|
||||
bool operator<(const Event& rhs) const
|
||||
{
|
||||
return cycles_from_now < rhs.cycles_from_now;
|
||||
}
|
||||
|
@ -25,4 +28,4 @@ void InitScheduler();
|
|||
void ScheduleEvent(Event event);
|
||||
void CheckScheduler(int cycles);
|
||||
|
||||
}
|
||||
} // namespace Scheduler
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// (c) Copyright 2022 Ryan Ilari
|
||||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include <app/Application.h>
|
||||
|
@ -9,9 +9,10 @@ int main(int argc, char** argv)
|
|||
{
|
||||
if (!Application::Init(argc, argv))
|
||||
{
|
||||
printf("[src/Main]: %s: Error initializing main app class\n", __FUNCTION__);
|
||||
printf("[src/Main]: %s: Error initializing main app class\n",
|
||||
__FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return Application::Run();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ inline char* print_128(uint128_t s)
|
|||
|
||||
memset(ret, 0, 512);
|
||||
|
||||
sprintf(ret, "%lx%016lx", s.u64[1], s.u64[0]);
|
||||
sprintf(ret, "%016lx %016lx", s.u64[1], s.u64[0]);
|
||||
|
||||
return ret;
|
||||
}
|
BIN
util/cmddecoder
Executable file
BIN
util/cmddecoder
Executable file
Binary file not shown.
24
util/cmddecoder.cpp
Normal file
24
util/cmddecoder.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "../src/util/uint128.h"
|
||||
|
||||
union SifRpcHeader
|
||||
{
|
||||
__uint128_t data;
|
||||
struct
|
||||
{
|
||||
__uint128_t psize : 8;
|
||||
__uint128_t dsize : 24;
|
||||
__uint128_t dest : 32;
|
||||
__uint128_t cid : 32;
|
||||
__uint128_t opt : 32;
|
||||
};
|
||||
};
|
||||
|
||||
uint8_t data[] = {0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
int main()
|
||||
{
|
||||
SifRpcHeader hdr;
|
||||
hdr.data = *(__uint128_t*)data;
|
||||
|
||||
printf("CMD ID: 0x%08x, %d\n", hdr.cid, hdr.opt);
|
||||
}
|
36
util/dmatag.cpp
Normal file
36
util/dmatag.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
union DMATag
|
||||
{
|
||||
__uint128_t value;
|
||||
|
||||
struct
|
||||
{
|
||||
__uint128_t qwc : 16;
|
||||
__uint128_t : 10;
|
||||
__uint128_t prio_control : 2;
|
||||
__uint128_t tag_id : 3;
|
||||
__uint128_t irq : 1;
|
||||
__uint128_t addr : 31;
|
||||
__uint128_t mem_sel : 1;
|
||||
__uint128_t data_transfer : 64;
|
||||
};
|
||||
};
|
||||
|
||||
uint8_t data[] = {0x03, 0x00, 0x00, 0x30, 0x40, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
int main()
|
||||
{
|
||||
DMATag tag;
|
||||
|
||||
tag.value = *(__uint128_t*)data;
|
||||
|
||||
printf("QWC: 0x%04x, prio_control: %d, tag_id: %d, irq: %d, addr: 0x%08x, mem_sel: %d, data_transfer: 0x%08lx\n", tag.qwc, tag.prio_control, tag.tag_id, tag.irq, tag.addr, tag.mem_sel, tag.data_transfer);
|
||||
|
||||
printf("%d\n", 0x1f % 0x1f);
|
||||
|
||||
return 0;
|
||||
}
|
BIN
util/dmatagdumper
Executable file
BIN
util/dmatagdumper
Executable file
Binary file not shown.
Loading…
Reference in a new issue