PIF stuff
This commit is contained in:
118
external/cic_nus_6105/n64_cic_nus_6105.cpp
vendored
Normal file
118
external/cic_nus_6105/n64_cic_nus_6105.cpp
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 X-Scale. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY X-Scale ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL X-Scale OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation are
|
||||||
|
* those of the authors and should not be interpreted as representing official
|
||||||
|
* policies, either expressed or implied, of X-Scale.
|
||||||
|
*
|
||||||
|
* This software provides an algorithm that emulates the protection scheme of
|
||||||
|
* N64 PIF/CIC-NUS-6105, by determining the proper response to each challenge.
|
||||||
|
* It was synthesized after a careful, exhaustive and detailed analysis of the
|
||||||
|
* challenge/response pairs stored in the 'pif2.dat' file from Project 64.
|
||||||
|
* These challenge/response pairs were the only resource used during this
|
||||||
|
* project. There was no kind of physical access to N64 hardware.
|
||||||
|
*
|
||||||
|
* This project would have never been possible without the contribuitions of
|
||||||
|
* the following individuals and organizations:
|
||||||
|
*
|
||||||
|
* - Oman: For being at the right place at the right time and being brave
|
||||||
|
* enough to pay a personal price so we could understand in a much deeper
|
||||||
|
* way how this magical console really works. We owe you so much.
|
||||||
|
*
|
||||||
|
* - Jovis: For all the positive energy and impressive hacking spirit that you
|
||||||
|
* shared with the N64 community. You were absolutely instrumental in
|
||||||
|
* several key events that shaped the N64 community in the last 14 years.
|
||||||
|
* Even if you're not physically with us anymore, your heritage, your
|
||||||
|
* knowledge and your attitude will never be forgotten.
|
||||||
|
*
|
||||||
|
* 'The candle that burns twice as bright burns half as long.'
|
||||||
|
*
|
||||||
|
* - LaC: For the endless contributions that you've given to the N64 community
|
||||||
|
* since the early days, when N64 was the next big thing. I've always
|
||||||
|
* admired the deep knowledge that you've gathered about the most little
|
||||||
|
* hardware details. Recently, you challanged us to find a small and
|
||||||
|
* concise algorithm that would emulate the behaviour of CIC-NUS-6105
|
||||||
|
* challenge/response protection scheme and here is the final result.
|
||||||
|
* LaC, Oman and Jovis were definitly the dream team of N64 reversing in
|
||||||
|
* the late 90's. Without your contributions, we would be much poorer.
|
||||||
|
*
|
||||||
|
* - marshall: For keeping the N64 scene alive during the last decade, when
|
||||||
|
* most people lost interest and moved along to different projects. You
|
||||||
|
* are the force that has been keeping us all together in the later
|
||||||
|
* years. When almost nobody cared about N64 anymore, you were always
|
||||||
|
* there, spreading the word, developing in the console, and lately,
|
||||||
|
* making impressive advances on the hardware side. I wish the best
|
||||||
|
* success to your new 64drive project.
|
||||||
|
*
|
||||||
|
* - hcs: For your contributions to the better understanding of the inner
|
||||||
|
* workings of the Reality Co-Processor (RCP). Your skills have impressed
|
||||||
|
* me for a long time now. And without your precious help by sharing your
|
||||||
|
* kownledge, I would have never understood the immense importance of
|
||||||
|
* Oman, Jovis and LaC achievements. Thank you !
|
||||||
|
*
|
||||||
|
* - Azimer & Tooie: For sharing with the N64 community your findings about the
|
||||||
|
* challenge/response pair used in 'Jet Force Gemini' and the 267
|
||||||
|
* challenge/response pairs used in 'Banjo Tooie', all stored in the
|
||||||
|
* 'pif2.dat' file of Project 64. They were instrumental to the final
|
||||||
|
* success of this endeavour.
|
||||||
|
*
|
||||||
|
* - Silicon Graphics, Inc. (SGI): For creating MIPS R4000, MIPS R4300 and
|
||||||
|
* Reality Co-Processor (RCP). You were the ultimate dream creator during
|
||||||
|
* the late 80's and early 90's. A very special word of gratitude goes to
|
||||||
|
* the two teams that during those years created RCP and MIPS R4300. They
|
||||||
|
* were technological breakthroughs back then.
|
||||||
|
*
|
||||||
|
* On a personal note, I would like to show my deepest gratitude to _Bijou_,
|
||||||
|
* for being always a source of endless hope and inspiration.
|
||||||
|
*
|
||||||
|
* -= X-Scale =- (#n64dev@EFnet)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "n64_cic_nus_6105.hpp"
|
||||||
|
|
||||||
|
void n64_cic_nus_6105(char chl[], char rsp[], int len)
|
||||||
|
{
|
||||||
|
static char lut0[0x10] = {
|
||||||
|
0x4, 0x7, 0xA, 0x7, 0xE, 0x5, 0xE, 0x1,
|
||||||
|
0xC, 0xF, 0x8, 0xF, 0x6, 0x3, 0x6, 0x9
|
||||||
|
};
|
||||||
|
static char lut1[0x10] = {
|
||||||
|
0x4, 0x1, 0xA, 0x7, 0xE, 0x5, 0xE, 0x1,
|
||||||
|
0xC, 0x9, 0x8, 0x5, 0x6, 0x3, 0xC, 0x9
|
||||||
|
};
|
||||||
|
char key, *lut;
|
||||||
|
int i, sgn, mag, mod;
|
||||||
|
|
||||||
|
for (key = 0xB, lut = lut0, i = 0; i < len; i++) {
|
||||||
|
rsp[i] = (key + 5 * chl[i]) & 0xF;
|
||||||
|
key = lut[rsp[i]];
|
||||||
|
sgn = (rsp[i] >> 3) & 0x1;
|
||||||
|
mag = ((sgn == 1) ? ~rsp[i] : rsp[i]) & 0x7;
|
||||||
|
mod = (mag % 3 == 1) ? sgn : 1 - sgn;
|
||||||
|
if (lut == lut1 && (rsp[i] == 0x1 || rsp[i] == 0x9))
|
||||||
|
mod = 1;
|
||||||
|
if (lut == lut1 && (rsp[i] == 0xB || rsp[i] == 0xE))
|
||||||
|
mod = 0;
|
||||||
|
lut = (mod == 1) ? lut1 : lut0;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
external/cic_nus_6105/n64_cic_nus_6105.hpp
vendored
Normal file
95
external/cic_nus_6105/n64_cic_nus_6105.hpp
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 X-Scale. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY X-Scale ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL X-Scale OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation are
|
||||||
|
* those of the authors and should not be interpreted as representing official
|
||||||
|
* policies, either expressed or implied, of X-Scale.
|
||||||
|
*
|
||||||
|
* This software provides an algorithm that emulates the protection scheme of
|
||||||
|
* N64 PIF/CIC-NUS-6105, by determining the proper response to each challenge.
|
||||||
|
* It was synthesized after a careful, exhaustive and detailed analysis of the
|
||||||
|
* challenge/response pairs stored in the 'pif2.dat' file from Project 64.
|
||||||
|
* These challenge/response pairs were the only resource used during this
|
||||||
|
* project. There was no kind of physical access to N64 hardware.
|
||||||
|
*
|
||||||
|
* This project would have never been possible without the contribuitions of
|
||||||
|
* the following individuals and organizations:
|
||||||
|
*
|
||||||
|
* - Oman: For being at the right place at the right time and being brave
|
||||||
|
* enough to pay a personal price so we could understand in a much deeper
|
||||||
|
* way how this magical console really works. We owe you so much.
|
||||||
|
*
|
||||||
|
* - Jovis: For all the positive energy and impressive hacking spirit that you
|
||||||
|
* shared with the N64 community. You were absolutely instrumental in
|
||||||
|
* several key events that shaped the N64 community in the last 14 years.
|
||||||
|
* Even if you're not physically with us anymore, your heritage, your
|
||||||
|
* knowledge and your attitude will never be forgotten.
|
||||||
|
*
|
||||||
|
* 'The candle that burns twice as bright burns half as long.'
|
||||||
|
*
|
||||||
|
* - LaC: For the endless contributions that you've given to the N64 community
|
||||||
|
* since the early days, when N64 was the next big thing. I've always
|
||||||
|
* admired the deep knowledge that you've gathered about the most little
|
||||||
|
* hardware details. Recently, you challanged us to find a small and
|
||||||
|
* concise algorithm that would emulate the behaviour of CIC-NUS-6105
|
||||||
|
* challenge/response protection scheme and here is the final result.
|
||||||
|
* LaC, Oman and Jovis were definitly the dream team of N64 reversing in
|
||||||
|
* the late 90's. Without your contributions, we would be much poorer.
|
||||||
|
*
|
||||||
|
* - marshall: For keeping the N64 scene alive during the last decade, when
|
||||||
|
* most people lost interest and moved along to different projects. You
|
||||||
|
* are the force that has been keeping us all together in the later
|
||||||
|
* years. When almost nobody cared about N64 anymore, you were always
|
||||||
|
* there, spreading the word, developing in the console, and lately,
|
||||||
|
* making impressive advances on the hardware side. I wish the best
|
||||||
|
* success to your new 64drive project.
|
||||||
|
*
|
||||||
|
* - hcs: For your contributions to the better understanding of the inner
|
||||||
|
* workings of the Reality Co-Processor (RCP). Your skills have impressed
|
||||||
|
* me for a long time now. And without your precious help by sharing your
|
||||||
|
* kownledge, I would have never understood the immense importance of
|
||||||
|
* Oman, Jovis and LaC achievements. Thank you !
|
||||||
|
*
|
||||||
|
* - Azimer & Tooie: For sharing with the N64 community your findings about the
|
||||||
|
* challenge/response pair used in 'Jet Force Gemini' and the 267
|
||||||
|
* challenge/response pairs used in 'Banjo Tooie', all stored in the
|
||||||
|
* 'pif2.dat' file of Project 64. They were instrumental to the final
|
||||||
|
* success of this endeavour.
|
||||||
|
*
|
||||||
|
* - Silicon Graphics, Inc. (SGI): For creating MIPS R4000, MIPS R4300 and
|
||||||
|
* Reality Co-Processor (RCP). You were the ultimate dream creator during
|
||||||
|
* the late 80's and early 90's. A very special word of gratitude goes to
|
||||||
|
* the two teams that during those years created RCP and MIPS R4300. They
|
||||||
|
* were technological breakthroughs back then.
|
||||||
|
*
|
||||||
|
* On a personal note, I would like to show my deepest gratitude to _Bijou_,
|
||||||
|
* for being always a source of endless hope and inspiration.
|
||||||
|
*
|
||||||
|
* -= X-Scale =- (#n64dev@EFnet)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CHL_LEN 0x20
|
||||||
|
|
||||||
|
void n64_cic_nus_6105(char chl[], char rsp[], int len);
|
||||||
@@ -38,8 +38,6 @@ include_directories(
|
|||||||
${SDL2_INCLUDE_DIRS}
|
${SDL2_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
set(NFD_PORTAL ON CACHE BOOL "Use dbus for native file dialog instead of gtk")
|
|
||||||
|
|
||||||
add_compile_definitions(SIMD_SUPPORT)
|
add_compile_definitions(SIMD_SUPPORT)
|
||||||
add_compile_options(-mssse3 -msse4.1)
|
add_compile_options(-mssse3 -msse4.1)
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ void Core::LoadROM(const std::string& rom_) {
|
|||||||
|
|
||||||
cpu->mem.LoadROM(rom);
|
cpu->mem.LoadROM(rom);
|
||||||
GameDB::match(cpu->mem);
|
GameDB::match(cpu->mem);
|
||||||
|
cpu->mem.mmio.si.pif.InitDevices(cpu->mem.saveType);
|
||||||
isPAL = cpu->mem.IsROMPAL();
|
isPAL = cpu->mem.IsROMPAL();
|
||||||
cpu->mem.mmio.si.pif.ExecutePIF(cpu->mem, cpu->regs);
|
cpu->mem.mmio.si.pif.ExecutePIF(cpu->mem, cpu->regs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ void LoadTAS(const char* filename) {
|
|||||||
loaded_tas_movie_index = sizeof(TASMovieHeader) - 4; // skip header
|
loaded_tas_movie_index = sizeof(TASMovieHeader) - 4; // skip header
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tas_movie_loaded() {
|
bool TasMovieLoaded() {
|
||||||
return loaded_tas_movie != nullptr;
|
return loaded_tas_movie != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ inline void LogController(const n64::Controller& controller) {
|
|||||||
Util::print("joy_y: {}\n\n", controller.joy_y);
|
Util::print("joy_y: {}\n\n", controller.joy_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
n64::Controller tas_next_inputs() {
|
n64::Controller TasNextInputs() {
|
||||||
if (loaded_tas_movie_index + sizeof(TASMovieControllerData) > loaded_tas_movie_size) {
|
if (loaded_tas_movie_index + sizeof(TASMovieControllerData) > loaded_tas_movie_size) {
|
||||||
loaded_tas_movie = nullptr;
|
loaded_tas_movie = nullptr;
|
||||||
n64::Controller empty_controller{};
|
n64::Controller empty_controller{};
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
|
|
||||||
void LoadTAS(const char* filename);
|
void LoadTAS(const char* filename);
|
||||||
void UnloadTAS();
|
void UnloadTAS();
|
||||||
n64::Controller tas_next_inputs();
|
n64::Controller TasNextInputs();
|
||||||
bool tas_movie_loaded();
|
bool TasMovieLoaded();
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
file(GLOB SOURCES *.cpp)
|
file(GLOB_RECURSE SOURCES *.cpp)
|
||||||
file(GLOB HEADERS *.hpp)
|
file(GLOB_RECURSE HEADERS *.hpp)
|
||||||
|
|
||||||
add_library(mmio ${SOURCES} ${HEADERS})
|
add_library(mmio ${SOURCES} ${HEADERS} ../../../../external/cic_nus_6105/n64_cic_nus_6105.cpp)
|
||||||
@@ -2,84 +2,98 @@
|
|||||||
#include <core/Mem.hpp>
|
#include <core/Mem.hpp>
|
||||||
#include <core/registers/Registers.hpp>
|
#include <core/registers/Registers.hpp>
|
||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <MupenMovie.hpp>
|
|
||||||
#include <SDL_keyboard.h>
|
#include <SDL_keyboard.h>
|
||||||
|
#include <cic_nus_6105/n64_cic_nus_6105.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
static int channel = 0;
|
void PIF::CICChallenge() {
|
||||||
|
u8 challenge[30];
|
||||||
|
u8 response[30];
|
||||||
|
|
||||||
void PIF::ProcessPIFCommands(Mem& mem) {
|
// Split 15 bytes into 30 nibbles
|
||||||
|
for (int i = 0; i < 15; i++) {
|
||||||
|
challenge[i * 2 + 0] = (pifRam[0x30 + i] >> 4) & 0x0F;
|
||||||
|
challenge[i * 2 + 1] = (pifRam[0x30 + i] >> 0) & 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
n64_cic_nus_6105((char*)challenge, (char*)response, CHL_LEN - 2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 15; i++) {
|
||||||
|
pifRam[0x30 + i] = (response[i * 2] << 4) + response[i * 2 + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIF::ProcessPIFCommands(Mem &mem) {
|
||||||
u8 control = pifRam[63];
|
u8 control = pifRam[63];
|
||||||
|
if (control & 1) {
|
||||||
if(control & 1) {
|
|
||||||
channel = 0;
|
channel = 0;
|
||||||
for(int i = 0; i < 63;) {
|
int i = 0;
|
||||||
|
while (i < 63) {
|
||||||
u8* cmd = &pifRam[i++];
|
u8* cmd = &pifRam[i++];
|
||||||
u8 t = cmd[0] & 0x3f;
|
u8 cmdlen = cmd[0] & 0x3F;
|
||||||
|
|
||||||
if(t == 0 || t == 0x3D) {
|
if (cmdlen == 0) {
|
||||||
channel++;
|
channel++;
|
||||||
} else if (t == 0x3E) {
|
} else if (cmdlen == 0x3D) { // 0xFD in PIF RAM = send reset signal to this pif channel
|
||||||
|
channel++;
|
||||||
|
} else if (cmdlen == 0x3E) { // 0xFE in PIF RAM = end of commands
|
||||||
break;
|
break;
|
||||||
} else if (t == 0x3F) {
|
} else if (cmdlen == 0x3F) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
u8 r = pifRam[i++];
|
u8 r = pifRam[i++];
|
||||||
r |= (1 << 7);
|
r |= (1 << 7);
|
||||||
if(r == 0xFE) {
|
if (r == 0xFE) { // 0xFE in PIF RAM = end of commands.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
u8 reslen = r & 0x3F; // TODO: out of bounds access possible on invalid data
|
||||||
|
u8* res = &pifRam[i + cmdlen];
|
||||||
|
|
||||||
u8 rlen = r & 0x3F;
|
switch (cmd[2]) {
|
||||||
u8* res = &pifRam[i + t];
|
|
||||||
switch(cmd[2]) {
|
|
||||||
case 0xff:
|
case 0xff:
|
||||||
res[0] = 0x05;
|
ControllerID(res);
|
||||||
res[1] = 0x00;
|
|
||||||
res[2] = 0x01;
|
|
||||||
channel++;
|
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
res[0] = 0x05;
|
ControllerID(res);
|
||||||
res[1] = 0x00;
|
|
||||||
res[2] = 0x01;
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if(tas_movie_loaded()) {
|
|
||||||
controller = tas_next_inputs();
|
|
||||||
} else {
|
|
||||||
UpdateController();
|
UpdateController();
|
||||||
|
if(!ReadButtons(res)) {
|
||||||
|
cmd[1] |= 0x80;
|
||||||
}
|
}
|
||||||
res[0] = controller.byte1;
|
channel++;
|
||||||
res[1] = controller.byte2;
|
|
||||||
res[2] = controller.joy_x;
|
|
||||||
res[3] = controller.joy_y;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
Util::print("MEMPAK READ\n");
|
//pif_mempack_read(cmd, res);
|
||||||
res[0] = 0;
|
//break;
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
Util::print("MEMPAK WRITE\n");
|
//pif_mempack_write(cmd, res);
|
||||||
res[0] = 0;
|
//break;
|
||||||
break;
|
|
||||||
case 4:
|
case 4:
|
||||||
Util::print("EEPROM READ\n");
|
//assert(mem.saveData != NULL && "EEPROM read when save data is uninitialized! Is this game in the game DB?");
|
||||||
res[0] = 0;
|
//pif_eeprom_read(cmd, res);
|
||||||
break;
|
//break;
|
||||||
case 5:
|
case 5:
|
||||||
Util::print("EEPROM WRITE\n");
|
//assert(mem.saveData != NULL && "EEPROM write when save data is uninitialized! Is this game in the game DB?");
|
||||||
|
//pif_eeprom_write(cmd, res);
|
||||||
res[0] = 0;
|
res[0] = 0;
|
||||||
break;
|
break;
|
||||||
default: Util::panic("Unimplemented PIF command {}", cmd[2]);
|
default:
|
||||||
|
Util::panic("Invalid PIF command: {:X}", cmd[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
i += t + rlen;
|
i += cmdlen + reslen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(control & 8) {
|
//if (control & 2) {
|
||||||
|
// CICChallenge();
|
||||||
|
// pifRam[63] &= ~2;
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (control & 0x08) {
|
||||||
pifRam[63] &= ~8;
|
pifRam[63] &= ~8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,13 +106,12 @@ void PIF::ProcessPIFCommands(Mem& mem) {
|
|||||||
#define GET_AXIS(gamepad, axis) SDL_GameControllerGetAxis(gamepad, axis)
|
#define GET_AXIS(gamepad, axis) SDL_GameControllerGetAxis(gamepad, axis)
|
||||||
|
|
||||||
void PIF::UpdateController() {
|
void PIF::UpdateController() {
|
||||||
const uint8_t* state = SDL_GetKeyboardState(nullptr);
|
|
||||||
s8 xaxis = 0, yaxis = 0;
|
s8 xaxis = 0, yaxis = 0;
|
||||||
|
|
||||||
if(gamepadConnected) {
|
if(gamepadConnected) {
|
||||||
bool A = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_A);
|
bool A = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_A);
|
||||||
bool B = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_X);
|
bool B = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_X);
|
||||||
bool Z = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_TRIGGERLEFT) == 32767;
|
bool Z = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_TRIGGERLEFT) == SDL_JOYSTICK_AXIS_MAX;
|
||||||
bool START = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_START);
|
bool START = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_START);
|
||||||
bool DUP = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_UP);
|
bool DUP = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_UP);
|
||||||
bool DDOWN = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
bool DDOWN = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
||||||
@@ -106,54 +119,55 @@ void PIF::UpdateController() {
|
|||||||
bool DRIGHT = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
bool DRIGHT = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
||||||
bool L = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
|
bool L = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
|
||||||
bool R = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
|
bool R = GET_BUTTON(gamepad, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
|
||||||
bool CUP = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTY) <= -128;
|
bool CUP = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTY) <= -127;
|
||||||
bool CDOWN = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTY) >= 127;
|
bool CDOWN = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTY) >= 127;
|
||||||
bool CLEFT = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTX) <= -128;
|
bool CLEFT = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTX) <= -127;
|
||||||
bool CRIGHT = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTX) >= 127;
|
bool CRIGHT = GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_RIGHTX) >= 127;
|
||||||
|
|
||||||
controller.a = A;
|
joybusDevices[channel].controller.a = A;
|
||||||
controller.b = B;
|
joybusDevices[channel].controller.b = B;
|
||||||
controller.z = Z;
|
joybusDevices[channel].controller.z = Z;
|
||||||
controller.start = START;
|
joybusDevices[channel].controller.start = START;
|
||||||
controller.dp_up = DUP;
|
joybusDevices[channel].controller.dp_up = DUP;
|
||||||
controller.dp_down = DDOWN;
|
joybusDevices[channel].controller.dp_down = DDOWN;
|
||||||
controller.dp_left = DLEFT;
|
joybusDevices[channel].controller.dp_left = DLEFT;
|
||||||
controller.dp_right = DRIGHT;
|
joybusDevices[channel].controller.dp_right = DRIGHT;
|
||||||
controller.joy_reset = L && R && START;
|
joybusDevices[channel].controller.joy_reset = L && R && START;
|
||||||
controller.l = L;
|
joybusDevices[channel].controller.l = L;
|
||||||
controller.r = R;
|
joybusDevices[channel].controller.r = R;
|
||||||
controller.c_up = CUP;
|
joybusDevices[channel].controller.c_up = CUP;
|
||||||
controller.c_down = CDOWN;
|
joybusDevices[channel].controller.c_down = CDOWN;
|
||||||
controller.c_left = CLEFT;
|
joybusDevices[channel].controller.c_left = CLEFT;
|
||||||
controller.c_right = CRIGHT;
|
joybusDevices[channel].controller.c_right = CRIGHT;
|
||||||
|
|
||||||
xaxis = (s8) std::clamp((GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_LEFTX) >> 8), -86, 86);
|
xaxis = (s8) std::clamp<s16>(GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_LEFTX), -86, 86);
|
||||||
yaxis = (s8) std::clamp(-(GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_LEFTY) >> 8), -86, 86);
|
yaxis = (s8) std::clamp<s16>(GET_AXIS(gamepad, SDL_CONTROLLER_AXIS_LEFTY), -86, 86);
|
||||||
|
|
||||||
controller.joy_x = xaxis;
|
joybusDevices[channel].controller.joy_x = xaxis;
|
||||||
controller.joy_y = yaxis;
|
joybusDevices[channel].controller.joy_y = -yaxis;
|
||||||
|
|
||||||
if (controller.joy_reset) {
|
if (joybusDevices[channel].controller.joy_reset) {
|
||||||
controller.start = false;
|
joybusDevices[channel].controller.start = false;
|
||||||
controller.joy_x = 0;
|
joybusDevices[channel].controller.joy_x = 0;
|
||||||
controller.joy_y = 0;
|
joybusDevices[channel].controller.joy_y = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
controller.a = state[SDL_SCANCODE_X];
|
const uint8_t* state = SDL_GetKeyboardState(nullptr);
|
||||||
controller.b = state[SDL_SCANCODE_C];
|
joybusDevices[channel].controller.a = state[SDL_SCANCODE_X];
|
||||||
controller.z = state[SDL_SCANCODE_Z];
|
joybusDevices[channel].controller.b = state[SDL_SCANCODE_C];
|
||||||
controller.start = state[SDL_SCANCODE_RETURN];
|
joybusDevices[channel].controller.z = state[SDL_SCANCODE_Z];
|
||||||
controller.dp_up = state[SDL_SCANCODE_KP_8];
|
joybusDevices[channel].controller.start = state[SDL_SCANCODE_RETURN];
|
||||||
controller.dp_down = state[SDL_SCANCODE_KP_5];
|
joybusDevices[channel].controller.dp_up = state[SDL_SCANCODE_KP_8];
|
||||||
controller.dp_left = state[SDL_SCANCODE_KP_4];
|
joybusDevices[channel].controller.dp_down = state[SDL_SCANCODE_KP_5];
|
||||||
controller.dp_right = state[SDL_SCANCODE_KP_6];
|
joybusDevices[channel].controller.dp_left = state[SDL_SCANCODE_KP_4];
|
||||||
controller.joy_reset = state[SDL_SCANCODE_RETURN] && state[SDL_SCANCODE_A] && state[SDL_SCANCODE_S];
|
joybusDevices[channel].controller.dp_right = state[SDL_SCANCODE_KP_6];
|
||||||
controller.l = state[SDL_SCANCODE_A];
|
joybusDevices[channel].controller.joy_reset = state[SDL_SCANCODE_RETURN] && state[SDL_SCANCODE_A] && state[SDL_SCANCODE_S];
|
||||||
controller.r = state[SDL_SCANCODE_S];
|
joybusDevices[channel].controller.l = state[SDL_SCANCODE_A];
|
||||||
controller.c_up = state[SDL_SCANCODE_I];
|
joybusDevices[channel].controller.r = state[SDL_SCANCODE_S];
|
||||||
controller.c_down = state[SDL_SCANCODE_J];
|
joybusDevices[channel].controller.c_up = state[SDL_SCANCODE_I];
|
||||||
controller.c_left = state[SDL_SCANCODE_K];
|
joybusDevices[channel].controller.c_down = state[SDL_SCANCODE_J];
|
||||||
controller.c_right = state[SDL_SCANCODE_L];
|
joybusDevices[channel].controller.c_left = state[SDL_SCANCODE_K];
|
||||||
|
joybusDevices[channel].controller.c_right = state[SDL_SCANCODE_L];
|
||||||
|
|
||||||
if (state[SDL_SCANCODE_LEFT]) {
|
if (state[SDL_SCANCODE_LEFT]) {
|
||||||
xaxis = -86;
|
xaxis = -86;
|
||||||
@@ -167,13 +181,13 @@ void PIF::UpdateController() {
|
|||||||
yaxis = 86;
|
yaxis = 86;
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.joy_x = xaxis;
|
joybusDevices[channel].controller.joy_x = xaxis;
|
||||||
controller.joy_y = yaxis;
|
joybusDevices[channel].controller.joy_y = yaxis;
|
||||||
|
|
||||||
if (controller.joy_reset) {
|
if (joybusDevices[channel].controller.joy_reset) {
|
||||||
controller.start = false;
|
joybusDevices[channel].controller.start = false;
|
||||||
controller.joy_x = 0;
|
joybusDevices[channel].controller.joy_x = 0;
|
||||||
controller.joy_y = 0;
|
joybusDevices[channel].controller.joy_y = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <MemoryRegions.hpp>
|
#include <MemoryRegions.hpp>
|
||||||
#include <SDL_gamecontroller.h>
|
#include <SDL_gamecontroller.h>
|
||||||
|
#include <GameDB.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
|
|
||||||
|
enum AccessoryType {
|
||||||
|
ACCESSORY_NONE,
|
||||||
|
ACCESSORY_MEMPACK,
|
||||||
|
ACCESSORY_RUMBLE_PACK
|
||||||
|
};
|
||||||
|
|
||||||
struct Controller {
|
struct Controller {
|
||||||
union {
|
union {
|
||||||
u8 byte1;
|
u8 byte1;
|
||||||
@@ -31,12 +38,30 @@ struct Controller {
|
|||||||
bool joy_reset:1;
|
bool joy_reset:1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
s8 joy_x;
|
s8 joy_x{};
|
||||||
s8 joy_y;
|
s8 joy_y{};
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(Controller) == 4);
|
static_assert(sizeof(Controller) == 4);
|
||||||
|
|
||||||
|
enum JoybusType {
|
||||||
|
JOYBUS_NONE,
|
||||||
|
JOYBUS_CONTROLLER,
|
||||||
|
JOYBUS_DANCEPAD,
|
||||||
|
JOYBUS_VRU,
|
||||||
|
JOYBUS_MOUSE,
|
||||||
|
JOYBUS_RANDNET_KEYBOARD,
|
||||||
|
JOYBUS_DENSHA_DE_GO,
|
||||||
|
JOYBUS_4KB_EEPROM,
|
||||||
|
JOYBUS_16KB_EEPROM
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JoybusDevice {
|
||||||
|
JoybusType type{};
|
||||||
|
AccessoryType accessoryType{};
|
||||||
|
Controller controller{};
|
||||||
|
};
|
||||||
|
|
||||||
struct Mem;
|
struct Mem;
|
||||||
struct Registers;
|
struct Registers;
|
||||||
|
|
||||||
@@ -64,23 +89,29 @@ struct CartInfo;
|
|||||||
|
|
||||||
struct PIF {
|
struct PIF {
|
||||||
void ProcessPIFCommands(Mem&);
|
void ProcessPIFCommands(Mem&);
|
||||||
|
void InitDevices(SaveType);
|
||||||
|
void CICChallenge();
|
||||||
void ExecutePIF(Mem& mem, Registers& regs);
|
void ExecutePIF(Mem& mem, Registers& regs);
|
||||||
void DoPIFHLE(Mem& mem, Registers& regs, bool pal, CICType cicType);
|
void DoPIFHLE(Mem& mem, Registers& regs, bool pal, CICType cicType);
|
||||||
void UpdateController();
|
void UpdateController();
|
||||||
|
bool ReadButtons(u8*);
|
||||||
bool gamepadConnected = false;
|
bool gamepadConnected = false;
|
||||||
|
void ControllerID(u8* res);
|
||||||
SDL_GameController* gamepad;
|
SDL_GameController* gamepad;
|
||||||
Controller controller;
|
JoybusDevice joybusDevices[6]{};
|
||||||
u8 pifBootrom[PIF_BOOTROM_SIZE]{}, pifRam[PIF_RAM_SIZE];
|
u8 pifBootrom[PIF_BOOTROM_SIZE]{}, pifRam[PIF_RAM_SIZE]{};
|
||||||
|
int channel = 0;
|
||||||
|
|
||||||
u8 Read(u32 addr) {
|
u8 Read(u32 addr) {
|
||||||
addr &= 0x7FF;
|
addr &= 0x7FF;
|
||||||
if(addr < 0x7c0) return pifBootrom[addr];
|
if(addr < 0x7c0) return pifBootrom[addr];
|
||||||
return pifRam[addr];
|
return pifRam[addr & PIF_RAM_DSIZE];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(u32 addr, u8 val) {
|
void Write(u32 addr, u8 val) {
|
||||||
addr &= 0x7FF;
|
addr &= 0x7FF;
|
||||||
if(addr < 0x7c0) return;
|
if(addr < 0x7c0) return;
|
||||||
pifRam[addr] = val;
|
pifRam[addr & PIF_RAM_DSIZE] = val;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
125
src/backend/core/mmio/PIF/Device.cpp
Normal file
125
src/backend/core/mmio/PIF/Device.cpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#include <PIF.hpp>
|
||||||
|
#include <MupenMovie.hpp>
|
||||||
|
#include "log.hpp"
|
||||||
|
|
||||||
|
namespace n64 {
|
||||||
|
void PIF::InitDevices(SaveType saveType) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
joybusDevices[i].type = JOYBUS_CONTROLLER; //TODO
|
||||||
|
if (joybusDevices[i].type) {
|
||||||
|
// TODO: make this configurable
|
||||||
|
joybusDevices[i].accessoryType = ACCESSORY_MEMPACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saveType == SAVE_EEPROM_4k) {
|
||||||
|
joybusDevices[4].type = JOYBUS_4KB_EEPROM;
|
||||||
|
} else if (saveType == SAVE_EEPROM_16k) {
|
||||||
|
joybusDevices[4].type = JOYBUS_16KB_EEPROM;
|
||||||
|
} else {
|
||||||
|
joybusDevices[4].type = JOYBUS_NONE;
|
||||||
|
}
|
||||||
|
joybusDevices[5].type = JOYBUS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIF::ControllerID(u8 *res) {
|
||||||
|
if (channel < 6) {
|
||||||
|
switch (joybusDevices[channel].type) {
|
||||||
|
case JOYBUS_NONE:
|
||||||
|
res[0] = 0x00;
|
||||||
|
res[1] = 0x00;
|
||||||
|
res[2] = 0x00;
|
||||||
|
break;
|
||||||
|
case JOYBUS_CONTROLLER:
|
||||||
|
res[0] = 0x05;
|
||||||
|
res[1] = 0x00;
|
||||||
|
res[2] = joybusDevices[channel].accessoryType != ACCESSORY_NONE ? 0x01 : 0x02;
|
||||||
|
break;
|
||||||
|
case JOYBUS_DANCEPAD:
|
||||||
|
res[0] = 0x05;
|
||||||
|
res[1] = 0x00;
|
||||||
|
res[2] = 0x00;
|
||||||
|
break;
|
||||||
|
case JOYBUS_VRU:
|
||||||
|
res[0] = 0x00;
|
||||||
|
res[1] = 0x01;
|
||||||
|
res[2] = 0x00;
|
||||||
|
break;
|
||||||
|
case JOYBUS_MOUSE:
|
||||||
|
res[0] = 0x02;
|
||||||
|
res[1] = 0x00;
|
||||||
|
res[2] = 0x00;
|
||||||
|
break;
|
||||||
|
case JOYBUS_RANDNET_KEYBOARD:
|
||||||
|
res[0] = 0x00;
|
||||||
|
res[1] = 0x02;
|
||||||
|
res[2] = 0x00;
|
||||||
|
break;
|
||||||
|
case JOYBUS_DENSHA_DE_GO:
|
||||||
|
res[0] = 0x20;
|
||||||
|
res[1] = 0x04;
|
||||||
|
res[2] = 0x00;
|
||||||
|
break;
|
||||||
|
case JOYBUS_4KB_EEPROM:
|
||||||
|
res[0] = 0x00;
|
||||||
|
res[1] = 0x80;
|
||||||
|
res[2] = 0x00;
|
||||||
|
break;
|
||||||
|
case JOYBUS_16KB_EEPROM:
|
||||||
|
res[0] = 0x00;
|
||||||
|
res[1] = 0xC0;
|
||||||
|
res[2] = 0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Util::panic("Device ID on unknown channel {}", channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
channel++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PIF::ReadButtons(u8* res) {
|
||||||
|
if(channel >= 6) {
|
||||||
|
res[0] = 0;
|
||||||
|
res[1] = 0;
|
||||||
|
res[2] = 0;
|
||||||
|
res[3] = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (joybusDevices[channel].type) {
|
||||||
|
case JOYBUS_NONE:
|
||||||
|
res[0] = 0x00;
|
||||||
|
res[1] = 0x00;
|
||||||
|
res[2] = 0x00;
|
||||||
|
res[3] = 0x00;
|
||||||
|
return false; // Device not present
|
||||||
|
case JOYBUS_CONTROLLER:
|
||||||
|
if (TasMovieLoaded()) {
|
||||||
|
// Load inputs from TAS movie
|
||||||
|
Controller controller = TasNextInputs();
|
||||||
|
res[0] = controller.byte1;
|
||||||
|
res[1] = controller.byte2;
|
||||||
|
res[2] = controller.joy_x;
|
||||||
|
res[3] = controller.joy_y;
|
||||||
|
} else {
|
||||||
|
// Load inputs normally
|
||||||
|
res[0] = joybusDevices[channel].controller.byte1;
|
||||||
|
res[1] = joybusDevices[channel].controller.byte2;
|
||||||
|
res[2] = joybusDevices[channel].controller.joy_x;
|
||||||
|
res[3] = joybusDevices[channel].controller.joy_y;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JOYBUS_DANCEPAD:
|
||||||
|
case JOYBUS_VRU:
|
||||||
|
case JOYBUS_MOUSE:
|
||||||
|
case JOYBUS_RANDNET_KEYBOARD:
|
||||||
|
case JOYBUS_DENSHA_DE_GO:
|
||||||
|
case JOYBUS_4KB_EEPROM:
|
||||||
|
case JOYBUS_16KB_EEPROM:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // Success!
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ void SI::Reset() {
|
|||||||
status.raw = 0;
|
status.raw = 0;
|
||||||
dramAddr = 0;
|
dramAddr = 0;
|
||||||
pifAddr = 0;
|
pifAddr = 0;
|
||||||
memset(&controller, 0, sizeof(Controller));
|
memset(&pif.joybusDevices, 0, sizeof(JoybusDevice) * 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SI::Read(MI& mi, u32 addr) const -> u32 {
|
auto SI::Read(MI& mi, u32 addr) const -> u32 {
|
||||||
@@ -40,10 +40,12 @@ void DMA(Mem& mem, Registers& regs) {
|
|||||||
for(int i = 0; i < 64; i++) {
|
for(int i = 0; i < 64; i++) {
|
||||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)] = si.pif.pifRam[i];
|
mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)] = si.pif.pifRam[i];
|
||||||
}
|
}
|
||||||
|
Util::debug("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})\n", si.pifAddr, si.dramAddr);
|
||||||
} else {
|
} else {
|
||||||
for(int i = 0; i < 64; i++) {
|
for(int i = 0; i < 64; i++) {
|
||||||
si.pif.pifRam[i] = mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)];
|
si.pif.pifRam[i] = mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)];
|
||||||
}
|
}
|
||||||
|
Util::debug("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})\n", si.dramAddr, si.pifAddr);
|
||||||
si.pif.ProcessPIFCommands(mem);
|
si.pif.ProcessPIFCommands(mem);
|
||||||
}
|
}
|
||||||
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
|
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
|
||||||
@@ -59,14 +61,12 @@ void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
|||||||
status.dmaBusy = true;
|
status.dmaBusy = true;
|
||||||
toDram = true;
|
toDram = true;
|
||||||
scheduler.enqueueRelative({SI_DMA_DELAY, DMA});
|
scheduler.enqueueRelative({SI_DMA_DELAY, DMA});
|
||||||
Util::debug("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})\n", pifAddr, dramAddr);
|
|
||||||
} break;
|
} break;
|
||||||
case 0x04800010: {
|
case 0x04800010: {
|
||||||
pifAddr = val & 0x1FFFFFFF;
|
pifAddr = val & 0x1FFFFFFF;
|
||||||
status.dmaBusy = true;
|
status.dmaBusy = true;
|
||||||
toDram = false;
|
toDram = false;
|
||||||
scheduler.enqueueRelative({4065*3, DMA});
|
scheduler.enqueueRelative({4065*3, DMA});
|
||||||
Util::debug("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})\n", dramAddr, pifAddr);
|
|
||||||
} break;
|
} break;
|
||||||
case 0x04800018:
|
case 0x04800018:
|
||||||
InterruptLower(mem.mmio.mi, regs, Interrupt::SI);
|
InterruptLower(mem.mmio.mi, regs, Interrupt::SI);
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ struct SI {
|
|||||||
SIStatus status{};
|
SIStatus status{};
|
||||||
u32 dramAddr{};
|
u32 dramAddr{};
|
||||||
u32 pifAddr{};
|
u32 pifAddr{};
|
||||||
Controller controller{};
|
|
||||||
|
|
||||||
bool toDram = false;
|
bool toDram = false;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user