diff --git a/src/frontend/App.cpp b/src/frontend/App.cpp index 42a0b90a..9363aee7 100644 --- a/src/frontend/App.cpp +++ b/src/frontend/App.cpp @@ -6,6 +6,9 @@ void App::Run() { // Main loop const u8* state = SDL_GetKeyboardState(nullptr); while (!core.done) { + core.Run(window); + core.UpdateController(state); + SDL_Event event; while (SDL_PollEvent(&event)) { ImGui_ImplSDL2_ProcessEvent(&event); @@ -36,10 +39,6 @@ void App::Run() { } break; } break; } - - core.UpdateController(state); } - - core.Run(window); } } diff --git a/src/frontend/imgui/Window.cpp b/src/frontend/imgui/Window.cpp index ecf73d25..bf629a11 100644 --- a/src/frontend/imgui/Window.cpp +++ b/src/frontend/imgui/Window.cpp @@ -3,6 +3,7 @@ #include #include #include +#include VkInstance instance{}; @@ -20,6 +21,8 @@ Window::Window(n64::Core& core) { void Window::InitSDL() { SDL_Init(SDL_INIT_EVERYTHING); + n64::InitAudio(); + window = SDL_CreateWindow( "natsukashii", SDL_WINDOWPOS_CENTERED, diff --git a/src/n64/Core.cpp b/src/n64/Core.cpp index 29a21dd4..c76c0158 100644 --- a/src/n64/Core.cpp +++ b/src/n64/Core.cpp @@ -38,6 +38,7 @@ void Core::LoadROM(const std::string& rom_) { void Core::Run(Window& window) { MMIO& mmio = mem.mmio; + Controller& controller = mmio.si.controller; int cycles = 0; for(int field = 0; field < mmio.vi.numFields; field++) { int frameCycles = 0; @@ -56,7 +57,7 @@ void Core::Run(Window& window) { mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp); mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp); - //mmio.ai.Step(mem, cpu.regs, 1); + mmio.ai.Step(mem, cpu.regs, 1); } cycles -= mmio.vi.cyclesPerHalfline; @@ -69,7 +70,7 @@ void Core::Run(Window& window) { UpdateScreenParallelRdp(*this, window, GetVI()); int missedCycles = N64_CYCLES_PER_FRAME - frameCycles; - //mmio.ai.Step(mem, cpu.regs, missedCycles); + mmio.ai.Step(mem, cpu.regs, missedCycles); } else if(pause && romLoaded) { UpdateScreenParallelRdp(*this, window, GetVI()); } else if(pause && !romLoaded) { diff --git a/src/n64/core/Audio.cpp b/src/n64/core/Audio.cpp index 15e10f3d..d5d88895 100644 --- a/src/n64/core/Audio.cpp +++ b/src/n64/core/Audio.cpp @@ -12,7 +12,7 @@ static SDL_AudioStream* audioStream = nullptr; SDL_mutex* audioStreamMutex; SDL_AudioSpec audioSpec; SDL_AudioSpec request; -SDL_AudioDeviceID audioDev; +SDL_AudioDeviceID audioDev{}; #define LockAudioMutex() SDL_LockMutex(audioStreamMutex) #define UnlockAudioMutex() SDL_UnlockMutex(audioStreamMutex) @@ -48,7 +48,9 @@ void InitAudio() { request.callback = audioCallback; request.userdata = nullptr; - audioDev = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0); + if(!audioDev) { + audioDev = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0); + } if(!audioDev) { util::panic("Failed to initialize SDL Audio: {}", SDL_GetError()); diff --git a/src/n64/core/Cpu.cpp b/src/n64/core/Cpu.cpp index 46e9fc27..9af85720 100644 --- a/src/n64/core/Cpu.cpp +++ b/src/n64/core/Cpu.cpp @@ -59,8 +59,12 @@ void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) { util::panic("BEV bit set!\n"); } else { switch(code) { - case Interrupt ... TLBModification: - case AddressErrorLoad ... Trap: + case Interrupt: case TLBModification: + case AddressErrorLoad: case AddressErrorStore: + case InstructionBusError: case DataBusError: + case Syscall: case Breakpoint: + case ReservedInstruction: case CoprocessorUnusable: + case Overflow: case Trap: case FloatingPointError: case Watch: regs.SetPC(s64(s32(0x80000180))); break; diff --git a/src/n64/core/Cpu.hpp b/src/n64/core/Cpu.hpp index 56e3a24b..25a3a4b2 100644 --- a/src/n64/core/Cpu.hpp +++ b/src/n64/core/Cpu.hpp @@ -7,16 +7,16 @@ namespace n64 { struct Cpu { Cpu() { - log = fopen("disasm.txt", "w"); - if(cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64, &handle) != CS_ERR_OK) { - util::panic("Could not initialize capstone!\n"); - } + //log = fopen("disasm.txt", "w"); + //if(cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64, &handle) != CS_ERR_OK) { + // util::panic("Could not initialize capstone!\n"); + //} Reset(); } ~Cpu() { - fclose(log); - cs_close(&handle); + //fclose(log); + //cs_close(&handle); } void Reset(); void Step(Mem&); diff --git a/src/n64/core/RSP.cpp b/src/n64/core/RSP.cpp index 3b6f8234..9cacc2a4 100644 --- a/src/n64/core/RSP.cpp +++ b/src/n64/core/RSP.cpp @@ -33,8 +33,8 @@ void RSP::Step(MI& mi, Registers& regs, RDP& rdp) { if(!spStatus.halt) { gpr[0] = 0; u32 instr = util::ReadAccess(imem, pc & IMEM_DSIZE); - oldPC = pc & 0xFFF; - pc = nextPC & 0xFFF; + oldPC = pc & 0xFFC; + pc = nextPC & 0xFFC; nextPC += 4; Exec(mi, regs, rdp, instr); } @@ -120,7 +120,7 @@ void RSP::Write(Mem& mem, Registers& regs, u32 addr, u32 value) { if(spStatus.halt) { oldPC = pc; pc = nextPC; - nextPC = value & 0xFFF; + nextPC = value & 0xFFC; } break; default: util::panic("Unimplemented SP register write {:08X}, val: {:08X}\n", addr, value); } diff --git a/src/n64/core/RSP.hpp b/src/n64/core/RSP.hpp index 67be6f33..3a221798 100644 --- a/src/n64/core/RSP.hpp +++ b/src/n64/core/RSP.hpp @@ -3,6 +3,12 @@ #include #include +#define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xfff]) +#define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1)) +#define SET_RSP_HALF(addr, value) do { RSP_BYTE(addr) = ((value) >> 8) & 0xFF; RSP_BYTE((addr) + 1) = (value) & 0xFF;} while(0) +#define GET_RSP_WORD(addr) ((GET_RSP_HALF(addr) << 16) | GET_RSP_HALF((addr) + 2)) +#define SET_RSP_WORD(addr, value) do { SET_RSP_HALF(addr, ((value) >> 16) & 0xFFFF); SET_RSP_HALF((addr) + 2, (value) & 0xFFFF);} while(0) + namespace n64 { union SPStatus { u32 raw; @@ -154,6 +160,30 @@ struct RSP { return val; } + inline u32 ReadWord(u32 addr) { + return GET_RSP_WORD(addr); + } + + inline void WriteWord(u32 addr, u32 val) { + SET_RSP_WORD(addr, val); + } + + inline u16 ReadHalf(u32 addr) { + return GET_RSP_HALF(addr); + } + + inline void WriteHalf(u32 addr, u16 val) { + SET_RSP_HALF(addr, val); + } + + inline u8 ReadByte(u32 addr) { + return GET_RSP_WORD(addr); + } + + inline void WriteByte(u32 addr, u8 val) { + SET_RSP_WORD(addr, val); + } + void add(u32 instr); void addi(u32 instr); void and_(u32 instr); diff --git a/src/n64/core/cpu/registers/Cop0.cpp b/src/n64/core/cpu/registers/Cop0.cpp index 68ff10a7..1026cbc4 100644 --- a/src/n64/core/cpu/registers/Cop0.cpp +++ b/src/n64/core/cpu/registers/Cop0.cpp @@ -11,9 +11,7 @@ Cop0::Cop0() { void Cop0::Reset() { cause.raw = 0xB000007C; status.raw = 0x241000E0; - wired = 64; - index = 64; - PRId = 0x00000B00; + PRId = 0x00000B22; Config = 0x7006E463; EPC = 0xFFFFFFFFFFFFFFFF; ErrorEPC = 0xFFFFFFFFFFFFFFFF; diff --git a/src/n64/core/mmio/AI.cpp b/src/n64/core/mmio/AI.cpp index a298bc84..fe6d3cc6 100644 --- a/src/n64/core/mmio/AI.cpp +++ b/src/n64/core/mmio/AI.cpp @@ -72,8 +72,8 @@ void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { } } -void AI::Step(Mem& mem, Registers& regs, int) { - cycles += cycles; +void AI::Step(Mem& mem, Registers& regs, int cpuCycles) { + cycles += cpuCycles; while(cycles > dac.period) { if (dmaCount == 0) { return; diff --git a/src/n64/core/mmio/PI.cpp b/src/n64/core/mmio/PI.cpp index d28fb501..5089062e 100644 --- a/src/n64/core/mmio/PI.cpp +++ b/src/n64/core/mmio/PI.cpp @@ -59,7 +59,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { cartAddr = cart_addr + len; InterruptRaise(mi, regs, Interrupt::PI); status &= 0xFFFFFFFE; - util::logdebug("PI DMA from rdram to cart (size: {:.2f} MiB)\n", (float)len / 1048576); + //util::logdebug("PI DMA from RDP RAM to CARTRIDGE (size: {} KiB, {:08X} to {:08X})\n", len, dramAddr, cartAddr); } break; case 0x0460000C: { u32 len = (val & 0x00FFFFFF) + 1; @@ -76,7 +76,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { cartAddr = cart_addr + len; InterruptRaise(mi, regs, Interrupt::PI); status &= 0xFFFFFFFE; - util::logdebug("PI DMA from cart to rdram (size: {:.2f} MiB)\n", (float)len / 1048576); + //util::logdebug("PI DMA from CARTRIDGE to RDP RAM (size: {} KiB, {:08X} to {:08X})\n", len, cartAddr, dramAddr); } break; case 0x04600010: if(val & 2) { diff --git a/src/n64/core/mmio/PIF.cpp b/src/n64/core/mmio/PIF.cpp index 3b986fd4..370dfe9b 100644 --- a/src/n64/core/mmio/PIF.cpp +++ b/src/n64/core/mmio/PIF.cpp @@ -65,7 +65,7 @@ void ProcessPIFCommands(u8* pifRam, Controller& controller, Mem& mem) { pifRam[63] = 128; } - //mem->pif_ram[63] &= ~1; + //pifRam[63] &= ~1; } } \ No newline at end of file diff --git a/src/n64/core/mmio/SI.cpp b/src/n64/core/mmio/SI.cpp index fb123afc..42aebfa0 100644 --- a/src/n64/core/mmio/SI.cpp +++ b/src/n64/core/mmio/SI.cpp @@ -34,23 +34,29 @@ void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { dramAddr = val; break; case 0x04800004: { - // if(!(status.raw & 3)) { - ProcessPIFCommands(mem.pifRam, controller, mem); + if(!(status.raw & 3)) { + ProcessPIFCommands(mem.pifRam, controller, mem); - u8 pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE; - memcpy(&mem.mmio.rdp.dram[dramAddr & RDRAM_DSIZE], - &mem.pifRam[pifAddr], 64); - InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); - status.intr = 1; + pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE; + for(int i = 0; i < 64; i++) { + mem.mmio.rdp.dram[BYTE_ADDRESS(dramAddr + i) & RDRAM_DSIZE] = mem.pifRam[pifAddr + i]; + } + InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); + status.intr = 1; + //util::logdebug("SI DMA from PIF RAM to RDP RAM ({:08X} to {:08X})\n", pifAddr, dramAddr); + } } break; case 0x04800010: { - //if(!(status.raw & 3)) { - u8 pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE; - memcpy(&mem.pifRam[pifAddr], - &mem.mmio.rdp.dram[dramAddr & RDRAM_DSIZE], 64); - ProcessPIFCommands(mem.pifRam, controller, mem); - InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); - status.intr = 1; + if(!(status.raw & 3)) { + pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE; + for(int i = 0; i < 64; i++) { + mem.pifRam[pifAddr + i] = mem.mmio.rdp.dram[BYTE_ADDRESS(dramAddr + i) & RDRAM_DSIZE]; + } + ProcessPIFCommands(mem.pifRam, controller, mem); + InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); + status.intr = 1; + //util::logdebug("SI DMA from RDP RAM to PIF RAM ({:08X} to {:08X})\n", dramAddr, pifAddr); + } } break; case 0x04800018: InterruptLower(mem.mmio.mi, regs, Interrupt::SI); diff --git a/src/n64/core/mmio/SI.hpp b/src/n64/core/mmio/SI.hpp index 1f05236e..f919de71 100644 --- a/src/n64/core/mmio/SI.hpp +++ b/src/n64/core/mmio/SI.hpp @@ -25,6 +25,7 @@ struct SI { void Reset(); SIStatus status{}; u32 dramAddr{}; + u32 pifAddr{}; Controller controller{}; auto Read(MI&, u32) const -> u32; diff --git a/src/n64/core/rsp/decode.cpp b/src/n64/core/rsp/decode.cpp index 4b8744ac..0d8042e1 100644 --- a/src/n64/core/rsp/decode.cpp +++ b/src/n64/core/rsp/decode.cpp @@ -1,26 +1,30 @@ #include #include #include +#include namespace n64 { -inline void special(RSP& rsp, u32 instr) { +inline void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) { u8 mask = instr & 0x3f; switch(mask) { - //case 0x00: rsp.sll(instr); break; - //case 0x04: rsp.sllv(instr); break; + case 0x00: rsp.sll(instr); break; + case 0x04: rsp.sllv(instr); break; //case 0x08: rsp.jr(instr); break; - //case 0x0C: - //case 0x0D: - // rsp.spStatus.halt = true; - // rsp.spStatus.broke = true; - // break; + case 0x0C: + case 0x0D: + rsp.spStatus.halt = true; + rsp.spStatus.broke = true; + if(rsp.spStatus.interruptOnBreak) { + InterruptRaise(mi, regs, Interrupt::SP); + } + break; //case 0x20: case 0x21: // rsp.add(instr); // break; - //case 0x24: rsp.and_(instr); break; - //case 0x25: rsp.or_(instr); break; + case 0x24: rsp.and_(instr); break; + case 0x25: rsp.or_(instr); break; //case 0x27: rsp.nor(instr); break; - default: util::panic("Unhandled RSP special instruction {} {}\n", (mask >> 3) & 7, mask & 7); + default: util::panic("Unhandled RSP special instruction ({:06b})\n", mask); } } @@ -56,7 +60,7 @@ inline void cop2(RSP& rsp, u32 instr) { case 0x00: switch(mask_sub) { //case 0x02: rsp.cfc2(instr); break; - default: util::panic("Unhandled RSP COP2 sub {} {}\n", (mask_sub >> 3) & 3, mask_sub & 3); + default: util::panic("Unhandled RSP COP2 sub ({:06b})\n", mask_sub); } break; //case 0x13: rsp.vabs(instr); break; @@ -64,40 +68,40 @@ inline void cop2(RSP& rsp, u32 instr) { //case 0x21: rsp.veq(instr); break; //case 0x22: rsp.vne(instr); break; //case 0x33: rsp.vmov(instr); break; - default: util::panic("Unhandled RSP COP2 {} {}\n", (mask >> 3) & 7, mask & 7); + default: util::panic("Unhandled RSP COP2 ({:06b})\n", mask); } } inline void cop0(MI& mi, Registers& regs, RSP& rsp, RDP& rdp, u32 instr) { u8 mask = (instr >> 21) & 0x1F; switch(mask) { - //case 0x00: rsp.mfc0(rdp, instr); break; - //case 0x04: rsp.mtc0(mi, regs, rdp, instr); break; - default: util::panic("Unhandled RSP COP0 {} {}\n", (mask >> 3) & 3, mask & 7); + case 0x00: rsp.mfc0(rdp, instr); break; + case 0x04: rsp.mtc0(mi, regs, rdp, instr); break; + default: util::panic("Unhandled RSP COP0 ({:06b})\n", mask); } } void RSP::Exec(MI &mi, Registers ®s, RDP &rdp, u32 instr) { u8 mask = (instr >> 26) & 0x3F; switch(mask) { - //case 0x00: special(*this, instr); break; + case 0x00: special(mi, regs, *this, instr); break; case 0x01: regimm(*this, instr); break; case 0x02: j(instr); break; - //case 0x03: jal(instr); break; - //case 0x04: b(instr, gpr[RT(instr)] == gpr[RS(instr)]); break; - //case 0x05: b(instr, gpr[RT(instr)] != gpr[RS(instr)]); break; - //case 0x07: b(instr, gpr[RS(instr)] > 0); break; + case 0x03: jal(instr); break; + case 0x04: b(instr, gpr[RT(instr)] == gpr[RS(instr)]); break; + case 0x05: b(instr, gpr[RT(instr)] != gpr[RS(instr)]); break; + case 0x07: b(instr, gpr[RS(instr)] > 0); break; case 0x08: case 0x09: addi(instr); break; - //case 0x0C: andi(instr); break; + case 0x0C: andi(instr); break; case 0x0D: ori(instr); break; - //case 0x0F: lui(instr); break; - //case 0x10: cop0(mi, regs, *this, rdp, instr); break; + case 0x0F: lui(instr); break; + case 0x10: cop0(mi, regs, *this, rdp, instr); break; //case 0x12: cop2(*this, instr); break; //case 0x21: lh(instr); break; - //case 0x23: lw(instr); break; + case 0x23: lw(instr); break; //case 0x28: sb(instr); break; //case 0x29: sh(instr); break; - //case 0x2B: sw(instr); break; + case 0x2B: sw(instr); break; //case 0x32: lwc2(*this, instr); break; //case 0x3A: swc2(*this, instr); break; default: util::panic("Unhandled RSP instruction ({:06b})\n", mask); diff --git a/src/n64/core/rsp/instructions.cpp b/src/n64/core/rsp/instructions.cpp index ad6a9a4b..44ee1c02 100644 --- a/src/n64/core/rsp/instructions.cpp +++ b/src/n64/core/rsp/instructions.cpp @@ -98,11 +98,11 @@ void RSP::addi(u32 instr) { } void RSP::and_(u32 instr) { - + gpr[RD(instr)] = gpr[RT(instr)] & gpr[RS(instr)]; } void RSP::andi(u32 instr) { - + gpr[RT(instr)] = gpr[RS(instr)] & (u16)instr; } void RSP::cfc2(u32 instr) { @@ -119,11 +119,13 @@ void RSP::lh(u32 instr) { } void RSP::lw(u32 instr) { - + u32 address = gpr[BASE(instr)] + (s16)instr; + gpr[RT(instr)] = ReadWord(address); } void RSP::lui(u32 instr) { - + u32 imm = ((u16)instr) << 16; + gpr[RT(instr)] = imm; } void RSP::lqv(u32 instr) { @@ -136,7 +138,8 @@ void RSP::j(u32 instr) { } void RSP::jal(u32 instr) { - + gpr[31] = nextPC; + j(instr); } void RSP::jr(u32 instr) { @@ -147,15 +150,15 @@ void RSP::nor(u32 instr) { } -void RSP::or_(u32 instr) { - -} - void RSP::ori(u32 instr) { s16 imm = instr; gpr[RT(instr)] = imm | gpr[RS(instr)]; } +void RSP::or_(u32 instr) { + gpr[RD(instr)] = gpr[RT(instr)] | gpr[RS(instr)]; +} + void RSP::sb(u32 instr) { } @@ -165,7 +168,8 @@ void RSP::sh(u32 instr) { } void RSP::sw(u32 instr) { - + u32 address = gpr[BASE(instr)] + (s16)instr; + WriteWord(address, gpr[RT(instr)]); } void RSP::sqv(u32 instr) { @@ -178,7 +182,8 @@ void RSP::sllv(u32 instr) { } void RSP::sll(u32 instr) { - + u8 sa = (instr >> 6) & 0x1f; + gpr[RD(instr)] = gpr[RT(instr)] << sa; } void RSP::vabs(u32 instr) {