mirror of https://github.com/bsnes-emu/bsnes.git
Update to v094r01 release.
byuu says: Changelog: - port: various compilation fixes for OS X [kode54] - nall: added programpath() function to return path to process binary [todo: need to have ethos use this function] - ruby: XAudio2 will select default game sound device instead of first sound device - ruby: DirectInput device IDs are no longer ambiguous when VID+PID are identical - ruby: OpenGL won't try and terminate if it hasn't been initialized - gb: D-pad up+down/left+right not masked in SGB mode - sfc: rewrote ICD2 video rendering to output in real-time, work with cycle-based Game Boy renderer - sfc: rewrote Bus::reduce(), reduces game loading time by about 500ms - ethos: store save states in {game}/higan/* instead of {game}/bsnes/* - loki: added target-loki/ (blank stub for now) - Makefile: purge out/* on make clean
This commit is contained in:
parent
10464b8c54
commit
04986d2bf7
4
Makefile
4
Makefile
|
@ -6,7 +6,8 @@ gb := gb
|
|||
gba := gba
|
||||
|
||||
profile := accuracy
|
||||
target := ethos
|
||||
target := ethos
|
||||
# target := loki
|
||||
|
||||
# options += debugger
|
||||
# arch := x86
|
||||
|
@ -77,6 +78,7 @@ flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
|
|||
|
||||
# targets
|
||||
clean:
|
||||
-@$(call delete,out/*)
|
||||
-@$(call delete,obj/*.o)
|
||||
-@$(call delete,obj/*.a)
|
||||
-@$(call delete,obj/*.so)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Emulator {
|
||||
static const char Name[] = "higan";
|
||||
static const char Version[] = "094";
|
||||
static const char Version[] = "094.01";
|
||||
static const char Author[] = "byuu";
|
||||
static const char License[] = "GPLv3";
|
||||
static const char Website[] = "http://byuu.org/";
|
||||
|
|
|
@ -20,9 +20,12 @@ void CPU::mmio_joyp_poll() {
|
|||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Left) << 1;
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Right) << 0;
|
||||
|
||||
//D-pad pivot makes it impossible to press opposing directions at the same time
|
||||
if(dpad & 4) dpad &= ~8; //disallow up+down
|
||||
if(dpad & 2) dpad &= ~1; //disallow left+right
|
||||
if(system.revision != System::Revision::SuperGameBoy) {
|
||||
//D-pad pivot makes it impossible to press opposing directions at the same time
|
||||
//however, Super Game Boy BIOS is able to set these bits together
|
||||
if(dpad & 4) dpad &= ~8; //disallow up+down
|
||||
if(dpad & 2) dpad &= ~1; //disallow left+right
|
||||
}
|
||||
|
||||
status.joyp = 0x0f;
|
||||
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req;
|
||||
|
|
|
@ -8,6 +8,10 @@ void Interface::lcdScanline() {
|
|||
if(hook) hook->lcdScanline();
|
||||
}
|
||||
|
||||
void Interface::lcdOutput(uint2 color) {
|
||||
if(hook) hook->lcdOutput(color);
|
||||
}
|
||||
|
||||
void Interface::joypWrite(bool p15, bool p14) {
|
||||
if(hook) hook->joypWrite(p15, p14);
|
||||
}
|
||||
|
|
|
@ -29,11 +29,13 @@ struct Interface : Emulator::Interface {
|
|||
//Super Game Boy bindings
|
||||
struct Hook {
|
||||
virtual void lcdScanline() {}
|
||||
virtual void lcdOutput(uint2 color) {}
|
||||
virtual void joypWrite(bool p15, bool p14) {}
|
||||
};
|
||||
Hook* hook = nullptr;
|
||||
|
||||
void lcdScanline();
|
||||
void lcdOutput(uint2 color);
|
||||
void joypWrite(bool p15, bool p14);
|
||||
|
||||
string title();
|
||||
|
|
|
@ -79,6 +79,7 @@ void PPU::dmg_run() {
|
|||
|
||||
uint32* output = screen + status.ly * 160 + px++;
|
||||
*output = color;
|
||||
interface->lcdOutput(color); //Super Game Boy notification
|
||||
}
|
||||
|
||||
void PPU::dmg_run_bg() {
|
||||
|
|
|
@ -25,6 +25,8 @@ void PPU::main() {
|
|||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
interface->lcdScanline(); //Super Game Boy notification
|
||||
|
||||
if(status.display_enable && status.ly < 144) {
|
||||
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
|
||||
add_clocks(92);
|
||||
|
@ -56,7 +58,6 @@ void PPU::scanline() {
|
|||
if(++status.ly == 154) frame();
|
||||
|
||||
if(status.ly < 144) {
|
||||
interface->lcdScanline(); //Super Game Boy rendering notification
|
||||
system.cgb() ? cgb_scanline() : dmg_scanline();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
#if defined(_WIN32)
|
||||
#elif defined(__APPLE__)
|
||||
#include <machine/endian.h>
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
struct Intrinsics {
|
||||
enum class Compiler : unsigned { Clang, GCC, VisualCPP, Unknown };
|
||||
enum class Platform : unsigned { Windows, MacOSX, X, Unknown }; //X = Linux, BSD, etc
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Math {
|
|||
#undef interface
|
||||
#define dllexport __declspec(dllexport)
|
||||
#else
|
||||
#include <endian.h>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#define dllexport
|
||||
|
|
|
@ -201,6 +201,7 @@ template<signed precision = 0, char padchar = '0'> inline string binary(uintmax_
|
|||
//platform.hpp
|
||||
inline string activepath();
|
||||
inline string realpath(const string& name);
|
||||
inline string programpath();
|
||||
inline string userpath();
|
||||
inline string configpath();
|
||||
inline string sharedpath();
|
||||
|
|
|
@ -22,6 +22,20 @@ string realpath(const string& name) {
|
|||
return result;
|
||||
}
|
||||
|
||||
string programpath() {
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
int argc = 0;
|
||||
wchar_t** argv = CommandLineToArgvW(GetCommandLine(), &argc);
|
||||
string argv0 = (const char*)utf8_t(argv[0]);
|
||||
LocalFree(argv);
|
||||
return realpath(argv0);
|
||||
#else
|
||||
Dl_info info;
|
||||
dladdr((void*)&programpath, &info);
|
||||
return realpath(info.dli_fname);
|
||||
#endif
|
||||
}
|
||||
|
||||
// /home/username/
|
||||
// c:/users/username/
|
||||
string userpath() {
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace nall {
|
|||
|
||||
//generate unique GUID
|
||||
inline string guid() {
|
||||
random_lfsr lfsr;
|
||||
LinearFeedbackShiftRegisterGenerator lfsr;
|
||||
lfsr.seed(time(nullptr));
|
||||
for(unsigned n = 0; n < 256; n++) lfsr();
|
||||
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
/*
|
||||
audio.xaudio2 (2010-08-14)
|
||||
author: OV2
|
||||
*/
|
||||
|
||||
#include "xaudio2.hpp"
|
||||
#include <windows.h>
|
||||
|
||||
|
@ -132,7 +127,19 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if(FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, 2, settings.frequency, 0, 0 , NULL))) {
|
||||
unsigned deviceCount = 0;
|
||||
pXAudio2->GetDeviceCount(&deviceCount);
|
||||
if(deviceCount == 0) { term(); return false; }
|
||||
|
||||
unsigned deviceID = 0;
|
||||
for(unsigned deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) {
|
||||
XAUDIO2_DEVICE_DETAILS deviceDetails;
|
||||
memset(&deviceDetails, 0, sizeof(XAUDIO2_DEVICE_DETAILS));
|
||||
pXAudio2->GetDeviceDetails(deviceIndex, &deviceDetails);
|
||||
if(deviceDetails.Role & DefaultGameDevice) deviceID = deviceIndex;
|
||||
}
|
||||
|
||||
if(FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasterVoice, 2, settings.frequency, 0, deviceID, NULL))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -145,7 +152,7 @@ public:
|
|||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
wfx.cbSize = 0;
|
||||
|
||||
if(FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx, XAUDIO2_VOICE_NOSRC , XAUDIO2_DEFAULT_FREQ_RATIO, this, NULL, NULL))) {
|
||||
if(FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx, XAUDIO2_VOICE_NOSRC, XAUDIO2_DEFAULT_FREQ_RATIO, this, NULL, NULL))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,18 +35,21 @@ struct pInputCarbon {
|
|||
group.input[inputID].value = value;
|
||||
}
|
||||
|
||||
void poll(vector<HID::Device*>& devices) {
|
||||
vector<HID::Device*> poll() {
|
||||
vector<HID::Device*> devices;
|
||||
|
||||
KeyMap keymap;
|
||||
GetKeys(keymap);
|
||||
uint8_t* buffer = (uint8_t*)keymap;
|
||||
|
||||
unsigned inputID = 0;
|
||||
for(auto& key : keys) {
|
||||
bool value = buffer[key.id >> 3] & (1 << (key.id & 7)));
|
||||
bool value = buffer[key.id >> 3] & (1 << (key.id & 7));
|
||||
assign(kb.hid, HID::Keyboard::GroupID::Button, inputID++, value);
|
||||
}
|
||||
|
||||
devices.append(&kb.hid);
|
||||
return devices;
|
||||
}
|
||||
|
||||
bool rumble(uint64_t id, bool enable) {
|
||||
|
|
|
@ -107,13 +107,9 @@ struct InputJoypadDirectInput {
|
|||
Joypad jp;
|
||||
jp.vendorID = instance->guidProduct.Data1 >> 0;
|
||||
jp.productID = instance->guidProduct.Data1 >> 16;
|
||||
jp.isXInputDevice = false;
|
||||
if(auto device = rawinput.find(jp.vendorID, jp.productID)) {
|
||||
jp.pathID = crc32_calculate((const uint8_t*)device().path.data(), device().path.size());
|
||||
jp.hid.id = (uint64_t)jp.pathID << 32 | jp.vendorID << 16 | jp.productID << 0;
|
||||
jp.isXInputDevice = device().isXInputDevice;
|
||||
} else {
|
||||
//this should never occur
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
//Microsoft has intentionally imposed artificial restrictions on XInput devices when used with DirectInput
|
||||
|
@ -133,6 +129,17 @@ struct InputJoypadDirectInput {
|
|||
device->EnumObjects(DirectInput_EnumJoypadEffectsCallback, (void*)this, DIDFT_FFACTUATOR);
|
||||
jp.hid.rumble = effects > 0;
|
||||
|
||||
DIPROPGUIDANDPATH property;
|
||||
memset(&property, 0, sizeof(DIPROPGUIDANDPATH));
|
||||
property.diph.dwSize = sizeof(DIPROPGUIDANDPATH);
|
||||
property.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
property.diph.dwObj = 0;
|
||||
property.diph.dwHow = DIPH_DEVICE;
|
||||
device->GetProperty(DIPROP_GUIDANDPATH, &property.diph);
|
||||
string devicePath = (const char*)utf8_t(property.wszPath);
|
||||
jp.pathID = crc32_calculate((const uint8_t*)devicePath.data(), devicePath.size());
|
||||
jp.hid.id = (uint64_t)jp.pathID << 32 | jp.vendorID << 16 | jp.productID << 0;
|
||||
|
||||
if(jp.hid.rumble) {
|
||||
//disable auto-centering spring for rumble support
|
||||
DIPROPDWORD property;
|
||||
|
|
|
@ -15,13 +15,12 @@ namespace ruby {
|
|||
namespace ruby {
|
||||
|
||||
struct pVideoCGL : OpenGL {
|
||||
RubyVideoCGL* view;
|
||||
RubyVideoCGL* view = nullptr;
|
||||
|
||||
struct {
|
||||
NSView* handle;
|
||||
|
||||
bool synchronize;
|
||||
unsigned filter;
|
||||
NSView* handle = nullptr;
|
||||
bool synchronize = false;
|
||||
unsigned filter = 0;
|
||||
string shader;
|
||||
} settings;
|
||||
|
||||
|
@ -157,14 +156,6 @@ struct pVideoCGL : OpenGL {
|
|||
}
|
||||
}
|
||||
|
||||
pVideoCGL() {
|
||||
view = nil;
|
||||
|
||||
settings.handle = nil;
|
||||
settings.synchronize = false;
|
||||
settings.filter = 0;
|
||||
}
|
||||
|
||||
~pVideoCGL() {
|
||||
term();
|
||||
}
|
||||
|
|
|
@ -200,11 +200,13 @@ bool OpenGL::init() {
|
|||
glrLinkProgram(program);
|
||||
|
||||
shader(nullptr);
|
||||
return true;
|
||||
return initialized = true;
|
||||
}
|
||||
|
||||
void OpenGL::term() {
|
||||
if(initialized == false) return;
|
||||
shader(nullptr); //release shader resources (eg frame[] history)
|
||||
OpenGLSurface::release();
|
||||
if(buffer) { delete[] buffer; buffer = nullptr; }
|
||||
initialized = false;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ struct OpenGL : OpenGLProgram {
|
|||
Setting(const string& name, const string& value) : name(name), value(value) {}
|
||||
};
|
||||
set<Setting> settings;
|
||||
bool initialized = false;
|
||||
|
||||
void shader(const char* pathname);
|
||||
void allocateHistory(unsigned size);
|
||||
|
|
|
@ -52,20 +52,19 @@ void ICD2::power() {
|
|||
void ICD2::reset() {
|
||||
create(ICD2::Enter, cpu.frequency / 5);
|
||||
|
||||
r6000_ly = 0x00;
|
||||
r6000_row = 0x00;
|
||||
r6003 = 0x00;
|
||||
r6004 = 0xff;
|
||||
r6005 = 0xff;
|
||||
r6006 = 0xff;
|
||||
r6007 = 0xff;
|
||||
for(auto& r : r7000) r = 0x00;
|
||||
r7800 = 0x0000;
|
||||
mlt_req = 0;
|
||||
|
||||
for(auto& n : lcd.buffer) n = 0;
|
||||
for(auto& n : lcd.output) n = 0;
|
||||
lcd.row = 0;
|
||||
for(auto& n : output) n = 0xff;
|
||||
read_bank = 0;
|
||||
read_addr = 0;
|
||||
write_bank = 0;
|
||||
write_addr = 0;
|
||||
|
||||
packetsize = 0;
|
||||
joyp_id = 3;
|
||||
|
|
|
@ -16,8 +16,8 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Coprocessor {
|
|||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
Emulator::Interface::Bind* bind;
|
||||
GameBoy::Interface::Hook* hook;
|
||||
Emulator::Interface::Bind* bind = nullptr;
|
||||
GameBoy::Interface::Hook* hook = nullptr;
|
||||
#include "interface/interface.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
};
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
#ifdef ICD2_CPP
|
||||
|
||||
//called on rendered lines 0-143 (not on Vblank lines 144-153)
|
||||
void ICD2::lcdScanline() {
|
||||
if(GameBoy::ppu.status.ly > 143) return; //Vblank
|
||||
if((GameBoy::ppu.status.ly & 7) == 0) {
|
||||
lcd.row = (lcd.row + 1) & 3;
|
||||
write_bank = (write_bank + 1) & 3;
|
||||
write_addr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned offset = (lcd.row * 160 * 8) + ((GameBoy::ppu.status.ly & 7) * 160);
|
||||
memcpy(lcd.buffer + offset, GameBoy::ppu.screen + GameBoy::ppu.status.ly * 160, 160 * sizeof(uint32));
|
||||
void ICD2::lcdOutput(uint2 color) {
|
||||
unsigned y = write_addr / 160;
|
||||
unsigned x = write_addr % 160;
|
||||
unsigned addr = write_bank * 512 + y * 2 + x / 8 * 16;
|
||||
output[addr + 0] = (output[addr + 0] << 1) | (bool)(color & 1);
|
||||
output[addr + 1] = (output[addr + 1] << 1) | (bool)(color & 2);
|
||||
write_addr = (write_addr + 1) % 1280;
|
||||
}
|
||||
|
||||
void ICD2::joypWrite(bool p15, bool p14) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
void lcdScanline();
|
||||
void lcdOutput(uint2 color);
|
||||
void joypWrite(bool p15, bool p14);
|
||||
|
||||
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue);
|
||||
|
|
|
@ -1,27 +1,12 @@
|
|||
#ifdef ICD2_CPP
|
||||
|
||||
//convert linear pixel data to 2bpp planar tiledata
|
||||
void ICD2::render(const uint32* source) {
|
||||
memset(lcd.output, 0x00, 320 * sizeof(uint16));
|
||||
|
||||
for(unsigned y = 0; y < 8; y++) {
|
||||
for(unsigned x = 0; x < 160; x++) {
|
||||
unsigned pixel = *source++;
|
||||
unsigned addr = y * 2 + (x / 8 * 16);
|
||||
lcd.output[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7));
|
||||
lcd.output[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 ICD2::read(unsigned addr) {
|
||||
addr &= 0xffff;
|
||||
|
||||
//LY counter
|
||||
if(addr == 0x6000) {
|
||||
r6000_ly = GameBoy::ppu.status.ly;
|
||||
r6000_row = lcd.row;
|
||||
return r6000_ly;
|
||||
unsigned y = min(143u, GameBoy::ppu.status.ly);
|
||||
return (y & ~7) | write_bank;
|
||||
}
|
||||
|
||||
//command ready port
|
||||
|
@ -47,8 +32,8 @@ uint8 ICD2::read(unsigned addr) {
|
|||
|
||||
//VRAM port
|
||||
if(addr == 0x7800) {
|
||||
uint8 data = lcd.output[r7800];
|
||||
r7800 = (r7800 + 1) % 320;
|
||||
uint8 data = output[read_bank * 512 + read_addr];
|
||||
read_addr = (read_addr + 1) & 511;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -60,12 +45,8 @@ void ICD2::write(unsigned addr, uint8 data) {
|
|||
|
||||
//VRAM port
|
||||
if(addr == 0x6001) {
|
||||
r6001 = data;
|
||||
r7800 = 0;
|
||||
|
||||
unsigned offset = (r6000_row - (4 - (r6001 - (r6000_ly & 3)))) & 3;
|
||||
render(lcd.buffer + offset * 160 * 8);
|
||||
|
||||
read_bank = data & 3;
|
||||
read_addr = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
void render(const uint32* source);
|
||||
|
||||
uint8 r6000_ly; //SGB BIOS' cache of LY
|
||||
uint8 r6000_row; //SGB BIOS' cache of ROW
|
||||
uint8 r6001; //VRAM conversion
|
||||
uint8 r6003; //control port
|
||||
uint8 r6004; //joypad 1
|
||||
uint8 r6005; //joypad 2
|
||||
uint8 r6006; //joypad 3
|
||||
uint8 r6007; //joypad 4
|
||||
uint8 r7000[16]; //JOYP packet data
|
||||
unsigned r7800; //VRAM offset
|
||||
uint8 mlt_req; //number of active joypads
|
||||
|
||||
struct LCD {
|
||||
uint32 buffer[4 * 160 * 8]; //four tile rows of linear video data
|
||||
uint16 output[320]; //one tile row of 2bpp video data
|
||||
unsigned row; //active ICD2 rendering tile row
|
||||
} lcd;
|
||||
uint8 output[4 * 512];
|
||||
unsigned read_bank;
|
||||
unsigned read_addr;
|
||||
unsigned write_bank;
|
||||
unsigned write_addr;
|
||||
|
|
|
@ -18,21 +18,19 @@ void ICD2::serialize(serializer& s) {
|
|||
s.integer(bitdata);
|
||||
s.integer(bitoffset);
|
||||
|
||||
s.integer(r6000_ly);
|
||||
s.integer(r6000_row);
|
||||
s.integer(r6001);
|
||||
s.integer(r6003);
|
||||
s.integer(r6004);
|
||||
s.integer(r6005);
|
||||
s.integer(r6006);
|
||||
s.integer(r6007);
|
||||
s.array(r7000);
|
||||
s.integer(r7800);
|
||||
s.integer(mlt_req);
|
||||
|
||||
s.array(lcd.buffer);
|
||||
s.array(lcd.output);
|
||||
s.integer(lcd.row);
|
||||
s.array(output);
|
||||
s.integer(read_bank);
|
||||
s.integer(read_addr);
|
||||
s.integer(write_bank);
|
||||
s.integer(write_addr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -56,31 +56,28 @@ MappedRAM::MappedRAM() : data_(nullptr), size_(0), write_protect_(false) {}
|
|||
//Bus
|
||||
|
||||
unsigned Bus::mirror(unsigned addr, unsigned size) {
|
||||
if(size == 0) return 0;
|
||||
unsigned base = 0;
|
||||
if(size) {
|
||||
unsigned mask = 1 << 23;
|
||||
while(addr >= size) {
|
||||
while(!(addr & mask)) mask >>= 1;
|
||||
addr -= mask;
|
||||
if(size > mask) {
|
||||
size -= mask;
|
||||
base += mask;
|
||||
}
|
||||
mask >>= 1;
|
||||
unsigned mask = 1 << 23;
|
||||
while(addr >= size) {
|
||||
while(!(addr & mask)) mask >>= 1;
|
||||
addr -= mask;
|
||||
if(size > mask) {
|
||||
size -= mask;
|
||||
base += mask;
|
||||
}
|
||||
base += addr;
|
||||
mask >>= 1;
|
||||
}
|
||||
return base;
|
||||
return base + addr;
|
||||
}
|
||||
|
||||
unsigned Bus::reduce(unsigned addr, unsigned mask) {
|
||||
unsigned result = 0, length = 0;
|
||||
for(unsigned n = 0; n < 24; n++) {
|
||||
unsigned bit = 1 << n;
|
||||
if(mask & bit) continue;
|
||||
result |= (bool)(addr & bit) << length++;
|
||||
while(mask) {
|
||||
unsigned bits = (mask & -mask) - 1;
|
||||
addr = ((addr >> 1) & ~bits) | (addr & bits);
|
||||
mask = (mask & (mask - 1)) >> 1;
|
||||
}
|
||||
return result;
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint8 Bus::read(unsigned addr) {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
namespace SuperFamicom {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const unsigned SerializerVersion = 27;
|
||||
static const unsigned SerializerVersion = 28;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,10 +54,10 @@ obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/)
|
|||
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/)
|
||||
obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/)
|
||||
|
||||
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
|
||||
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/)
|
||||
$(compiler) $(rubyflags) -c $< -o $@
|
||||
|
||||
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
|
||||
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/)
|
||||
$(compiler) $(phoenixflags) -c $< -o $@
|
||||
|
||||
obj/resource.o: $(ui)/resource.rc
|
||||
|
@ -99,7 +99,6 @@ else
|
|||
sudo install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name)
|
||||
sudo install -D -m 644 data/$(name).png $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
|
||||
sudo install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop
|
||||
|
||||
sudo mkdir -p /usr/share/$(name)
|
||||
sudo cp -R profile/* /usr/share/$(name)
|
||||
sudo cp data/cheats.bml /usr/share/$(name)/cheats.bml
|
||||
|
|
|
@ -89,7 +89,7 @@ void Utility::load() {
|
|||
presentation->setTitle(system().title());
|
||||
|
||||
cheatEditor->load({pathname[0], "cheats.bml"});
|
||||
stateManager->load({pathname[0], "bsnes/states.bsa"}, 1);
|
||||
stateManager->load({pathname[0], "higan/states.bsa"}, 1);
|
||||
|
||||
synchronizeDSP();
|
||||
|
||||
|
@ -104,7 +104,7 @@ void Utility::unload() {
|
|||
if(tracerEnable) tracerToggle();
|
||||
|
||||
cheatEditor->save({pathname[0], "cheats.bml"});
|
||||
stateManager->save({pathname[0], "bsnes/states.bsa"}, 1);
|
||||
stateManager->save({pathname[0], "higan/states.bsa"}, 1);
|
||||
|
||||
system().unload();
|
||||
path.reset();
|
||||
|
@ -125,14 +125,14 @@ void Utility::saveState(unsigned slot) {
|
|||
if(program->active == nullptr) return;
|
||||
serializer s = system().serialize();
|
||||
if(s.size() == 0) return;
|
||||
directory::create({pathname[0], "bsnes/"});
|
||||
if(file::write({pathname[0], "bsnes/state-", slot, ".bsa"}, s.data(), s.size()) == false);
|
||||
directory::create({pathname[0], "higan/"});
|
||||
if(file::write({pathname[0], "higan/state-", slot, ".bsa"}, s.data(), s.size()) == false);
|
||||
showMessage({"Saved to slot ", slot});
|
||||
}
|
||||
|
||||
void Utility::loadState(unsigned slot) {
|
||||
if(program->active == nullptr) return;
|
||||
auto memory = file::read({pathname[0], "bsnes/state-", slot, ".bsa"});
|
||||
auto memory = file::read({pathname[0], "higan/state-", slot, ".bsa"});
|
||||
if(memory.size() == 0) return showMessage({"Unable to locate slot ", slot, " state"});
|
||||
serializer s(memory.data(), memory.size());
|
||||
if(system().unserialize(s) == false) return showMessage({"Slot ", slot, " state incompatible"});
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
name := loki
|
||||
|
||||
processors := arm gsu hg51b lr35902 r65816 spc700 upd96050
|
||||
include processor/Makefile
|
||||
|
||||
include sfc/Makefile
|
||||
include gb/Makefile
|
||||
|
||||
ui_objects := ui-loki
|
||||
ui_objects += phoenix
|
||||
ui_objects += $(if $(call streq,$(platform),windows),resource)
|
||||
|
||||
include phoenix/Makefile
|
||||
link += $(phoenixlink)
|
||||
|
||||
objects := $(ui_objects) $(objects)
|
||||
objects := $(patsubst %,obj/%.o,$(objects))
|
||||
|
||||
obj/ui-loki.o: $(ui)/loki.cpp $(call rwildcard,$(ui)/)
|
||||
|
||||
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/)
|
||||
$(compiler) $(phoenixflags) -c $< -o $@
|
||||
|
||||
obj/resource.o: $(ui)/resource.rc
|
||||
ifeq ($(arch),win32)
|
||||
windres --target=pe-i386 $(ui)/resource.rc obj/resource.o
|
||||
else
|
||||
windres $(ui)/resource.rc obj/resource.o
|
||||
endif
|
||||
|
||||
build: $(objects)
|
||||
ifeq ($(platform),windows)
|
||||
$(strip $(compiler) -shared -o out/phoenix.dll obj/phoenix.o $(phoenixlink))
|
||||
$(strip $(compiler) -o out/$(name) $(subst obj/phoenix.o,,$(objects)) $(link) -Lout -lphoenix)
|
||||
else ifeq ($(platform),macosx)
|
||||
if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi
|
||||
mkdir out/$(name).app
|
||||
mkdir out/$(name).app/Contents
|
||||
mkdir out/$(name).app/Contents/MacOS
|
||||
mkdir out/$(name).app/Contents/Resources
|
||||
cp data/Info.plist out/$(name).app/Contents/Info.plist
|
||||
$(strip $(compiler) -o out/$(name).app/Contents/MacOS/$(name) $(objects) $(link))
|
||||
else
|
||||
$(strip $(compiler) -o out/$(name) $(objects) $(link))
|
||||
endif
|
||||
|
||||
install:
|
||||
ifeq ($(platform),windows)
|
||||
else ifeq ($(platform),macosx)
|
||||
sudo mkdir -p /Library/Application\ Support/$(name)
|
||||
sudo cp -R profile/* /Library/Application\ Support/$(name)
|
||||
sudo chmod -R 777 /Library/Application\ Support/$(name)
|
||||
else
|
||||
sudo install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name)
|
||||
sudo mkdir -p /usr/share/$(name)
|
||||
sudo cp -R profile/* /usr/share/$(name)
|
||||
sudo chmod -R 777 /usr/share/$(name)
|
||||
endif
|
||||
|
||||
uninstall:
|
||||
ifeq ($(platform),windows)
|
||||
else ifeq ($(platform),macosx)
|
||||
else
|
||||
sudo rm $(DESTDIR)$(prefix)/bin/$(name)
|
||||
endif
|
|
@ -0,0 +1,38 @@
|
|||
#include "loki.hpp"
|
||||
|
||||
Program* program = nullptr;
|
||||
DSP dspaudio;
|
||||
|
||||
string Program::path(string name) {
|
||||
string path = {basepath, name};
|
||||
if(file::exists(path) || directory::exists(path)) return path;
|
||||
path = {userpath, name};
|
||||
if(file::exists(path) || directory::exists(path)) return path;
|
||||
path = {sharedpath, name};
|
||||
if(file::exists(path) || directory::exists(path)) return path;
|
||||
return {userpath, name};
|
||||
}
|
||||
|
||||
void Program::main() {
|
||||
}
|
||||
|
||||
Program::Program(int argc, char** argv) {
|
||||
program = this;
|
||||
|
||||
basepath = nall::programpath();
|
||||
userpath = {nall::configpath(), "loki/"};
|
||||
sharedpath = {nall::sharedpath(), "loki/"};
|
||||
directory::create(userpath);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
utf8_args(argc, argv);
|
||||
#endif
|
||||
|
||||
Application::setName("loki");
|
||||
new Program(argc, argv);
|
||||
delete program;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#include <emulator/emulator.hpp>
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/config.hpp>
|
||||
#include <nall/directory.hpp>
|
||||
#include <nall/dsp.hpp>
|
||||
#include <nall/invoke.hpp>
|
||||
#include <nall/map.hpp>
|
||||
#include <nall/stream/file.hpp>
|
||||
#include <nall/stream/memory.hpp>
|
||||
#include <nall/stream/mmap.hpp>
|
||||
#include <nall/stream/vector.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <phoenix/phoenix.hpp>
|
||||
using namespace phoenix;
|
||||
|
||||
struct Program {
|
||||
string basepath;
|
||||
string userpath;
|
||||
string sharedpath;
|
||||
|
||||
string path(string name);
|
||||
void main();
|
||||
Program(int argc, char** argv);
|
||||
};
|
||||
|
||||
extern Program* program;
|
||||
extern DSP dspaudio;
|
Loading…
Reference in New Issue