Started tidying, first SIF transfer

This commit is contained in:
Your Name 2023-02-01 08:08:01 -05:00
parent 923d19a971
commit da6fdef63a
33 changed files with 1118 additions and 436 deletions

View file

@ -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());

View file

@ -17,4 +17,4 @@ void Reset();
void Run();
void Dump();
}
}

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();
}

View file

@ -77,7 +77,7 @@ public:
cg = new Xbyak::CodeGenerator(0xffffffff, base);
}
const uint8_t* GetFreeBase();
uint8_t* GetFreeBase();
};
extern Emitter* emit;

View file

@ -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);

View file

@ -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();
}
}

View file

@ -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()

View file

@ -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();

View file

@ -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()

View 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
View file

@ -0,0 +1,10 @@
#pragma once
#include <cstdint>
namespace Timers
{
void WriteTimerMode(int timer, uint32_t data);
}

View file

@ -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;
}
}

View file

@ -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();
};
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -16,4 +16,4 @@ inline void WriteGSSYNCH1(uint64_t data) {}
inline void WriteGSSYNCH2(uint64_t data) {}
inline void WriteGSSYNCV(uint64_t data) {}
}
} // namespace GS

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();
}
}

View file

@ -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

Binary file not shown.

24
util/cmddecoder.cpp Normal file
View 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
View 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

Binary file not shown.