//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2018-2018 Phil Smith // // This file is part of Nestopia. // // Nestopia is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Nestopia is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include "NstCpu.hpp" #include "NstHomebrew.hpp" namespace Nes { namespace Core { #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Homebrew::Homebrew(Cpu& c) : cpu(c) , exitAddress(0) , exitSet(false) , exitPort(NULL) , stdOutAddress(0) , stdOutSet(false) , stdOutPort(NULL) , stdErrAddress(0) , stdErrSet(false) , stdErrPort(NULL) {} Homebrew::~Homebrew() { ClearPorts(); } void Homebrew::Reset() { ActivateExitPort(); ActivateStdOutPort(); ActivateStdErrPort(); } void Homebrew::ClearPorts() { ClearExitPort(); ClearStdOutPort(); ClearStdErrPort(); } Result Homebrew::SetExitPort ( const word address, const bool activate ) { if ( exitSet && exitAddress == address && (!activate || exitPort != NULL) ) return RESULT_NOP; ClearExitPort(); exitAddress = address; exitSet = true; if (activate) return ActivateExitPort(); else return RESULT_OK; } Result Homebrew::ClearExitPort() { exitSet = false; if (exitPort != NULL) { cpu.Unlink ( exitAddress, this, &Homebrew::Peek_Exit, &Homebrew::Poke_Exit ); exitPort = NULL; return RESULT_OK; } else return RESULT_NOP; } Result Homebrew::SetStdOutPort ( const word address, const bool activate ) { if ( stdOutSet && stdOutAddress == address && (!activate || stdOutPort != NULL) ) return RESULT_NOP; ClearStdOutPort(); stdOutAddress = address; stdOutSet = true; if (activate) return ActivateStdOutPort(); else return RESULT_OK; } Result Homebrew::ClearStdOutPort() { stdOutSet = false; if (stdOutPort != NULL) { cpu.Unlink ( stdOutAddress, this, &Homebrew::Peek_StdOut, &Homebrew::Poke_StdOut ); stdOutPort = NULL; return RESULT_OK; } else return RESULT_NOP; } Result Homebrew::SetStdErrPort ( const word address, const bool activate ) { if ( stdErrSet && stdErrAddress == address && (!activate || stdErrPort != NULL) ) return RESULT_NOP; ClearStdErrPort(); stdErrAddress = address; stdErrSet = true; if (activate) return ActivateStdErrPort(); else return RESULT_OK; } Result Homebrew::ClearStdErrPort() { stdErrSet = false; if (stdErrPort != NULL) { cpu.Unlink ( stdErrAddress, this, &Homebrew::Peek_StdErr, &Homebrew::Poke_StdErr ); stdErrPort = NULL; return RESULT_OK; } else return RESULT_NOP; } dword Homebrew::NumPorts() const { return (exitPort != NULL ? 1 : 0) + (stdOutPort != NULL ? 1 : 0) + (stdErrPort != NULL ? 1 : 0); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif NES_PEEK_A(Homebrew,Exit) { return exitPort->Peek( address ); } NES_POKE_D(Homebrew,Exit) { std::exit( data ); } NES_PEEK_A(Homebrew,StdOut) { return stdOutPort->Peek( address ); } NES_POKE_D(Homebrew,StdOut) { std::cout << (static_cast(data & 0xFF)); if (data == '\n') std::cout << std::flush; } NES_PEEK_A(Homebrew,StdErr) { return stdErrPort->Peek( address ); } NES_POKE_D(Homebrew,StdErr) { std::cerr << (static_cast(data & 0xFF)); if (data == '\n') std::cerr << std::flush; } Result Homebrew::ActivateExitPort() { if (exitSet && exitPort == NULL) { exitPort = cpu.Link ( exitAddress, Cpu::LEVEL_HIGH, this, &Homebrew::Peek_Exit, &Homebrew::Poke_Exit ); return RESULT_OK; } else return RESULT_NOP; } Result Homebrew::ActivateStdOutPort() { if (stdOutSet && stdOutPort == NULL) { stdOutPort = cpu.Link ( stdOutAddress, Cpu::LEVEL_HIGH, this, &Homebrew::Peek_StdOut, &Homebrew::Poke_StdOut ); return RESULT_OK; } else return RESULT_NOP; } Result Homebrew::ActivateStdErrPort() { if (stdErrSet && stdErrPort == NULL) { stdErrPort = cpu.Link ( stdErrAddress, Cpu::LEVEL_HIGH, this, &Homebrew::Peek_StdErr, &Homebrew::Poke_StdErr ); return RESULT_OK; } else return RESULT_NOP; } } }