Update to v085r04 release.

byuu says:

Changelog:
- added base/ folder
- base/base.hpp defines the version number for all UI targets, all the
  varint-types, and a hook() class for debugger functions (see below)
- fixed compatibility profile compilation
- removed within<> template from the SNES target
- the SNES core can be built without Game Boy support now, if you so
  choose (my SNES debugger is not going to support debugging the GBZ80,
  sorry.)
- added ui-debugger; not at all useful right now, will be a long while
  to get something usable ready

So hook is a class wrapper around nall::function. It allows you to
invoke potentially empty functions (and as such, the return type must
have a trivial constructor.)
It also doesn't actually perform the test+invocation when DEBUGGER
(options=debugger) is not defined. So you should have no overhead in
regular builds.
The core classes now have a subclass with all the debugging hooks, so
you'll see eg:

    void CPU::op_step() {
      debugger.op_exec(regs.pc);
      (this->*opcode_table[op_read()])();
    }

Clear what it's doing, clear what it's for. A whole lot less work than
inheriting the whole CPU core and virtualizing the functions we want to
hook.
All the logic for what to do inside these callbacks will be handled by
individual debuggers, so they can have all the functionality they want.
This commit is contained in:
Tim Allen 2012-02-06 23:03:45 +11:00
parent 892bb3ab01
commit 730e6ae4cc
32 changed files with 659 additions and 221 deletions

View File

@ -4,10 +4,10 @@ nes := nes
snes := snes snes := snes
gameboy := gameboy gameboy := gameboy
profile := accuracy profile := accuracy
ui := ui ui := ui-debugger
# options += console # options += console
# options += debugger options += debugger
# compiler # compiler
c := $(compiler) -std=gnu99 c := $(compiler) -std=gnu99
@ -39,8 +39,6 @@ else
unknown_platform: help; unknown_platform: help;
endif endif
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
# implicit rules # implicit rules
compile = \ compile = \
$(strip \ $(strip \
@ -59,6 +57,7 @@ all: build;
obj/libco.o: libco/libco.c libco/* obj/libco.o: libco/libco.c libco/*
include $(ui)/Makefile include $(ui)/Makefile
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
# targets # targets
clean: clean:
@ -91,6 +90,6 @@ sync:
rm -r phoenix/test rm -r phoenix/test
archive-all: archive-all:
tar -cjf bsnes.tar.bz2 data gameboy libco nall nes obj out phoenix ruby snes ui ui-libsnes Makefile cc.bat clean.bat tar -cjf bsnes.tar.bz2 base data gameboy libco nall nes obj out phoenix ruby snes ui ui-debugger ui-libsnes Makefile cc.bat clean.bat
help:; help:;

120
bsnes/base/base.hpp Executable file
View File

@ -0,0 +1,120 @@
#ifndef BASE_HPP
#define BASE_HPP
const char Version[] = "085.04";
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>
#include <nall/any.hpp>
#include <nall/array.hpp>
#include <nall/dl.hpp>
#include <nall/dsp.hpp>
#include <nall/endian.hpp>
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/moduloarray.hpp>
#include <nall/priorityqueue.hpp>
#include <nall/property.hpp>
#include <nall/random.hpp>
#include <nall/serializer.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>
using namespace nall;
//debugging function hook:
//no overhead (and no debugger invocation) if not compiled with -DDEBUGGER
//wraps testing of function to allow invocation without a defined callback
template<typename T> struct hook;
template<typename R, typename... P> struct hook<R (P...)> {
function<R (P...)> callback;
R operator()(P... p) const {
#if defined(DEBUGGER)
if(callback) return callback(std::forward<P>(p)...);
#endif
return R();
}
hook() {}
hook(void *function) { callback = function; }
hook(R (*function)(P...)) { callback = function; }
template<typename C> hook(R (C::*function)(P...), C *object) { callback = { function, object }; }
template<typename C> hook(R (C::*function)(P...) const, C *object) { callback = { function, object }; }
template<typename L> hook(const L& function) { callback = function; }
hook& operator=(const function<R (P...)> &function) { callback = function; return *this; }
};
typedef int_t< 1> int1;
typedef int_t< 2> int2;
typedef int_t< 3> int3;
typedef int_t< 4> int4;
typedef int_t< 5> int5;
typedef int_t< 6> int6;
typedef int_t< 7> int7;
typedef int8_t int8;
typedef int_t< 9> int9;
typedef int_t<10> int10;
typedef int_t<11> int11;
typedef int_t<12> int12;
typedef int_t<13> int13;
typedef int_t<14> int14;
typedef int_t<15> int15;
typedef int16_t int16;
typedef int_t<17> int17;
typedef int_t<18> int18;
typedef int_t<19> int19;
typedef int_t<20> int20;
typedef int_t<21> int21;
typedef int_t<22> int22;
typedef int_t<23> int23;
typedef int_t<24> int24;
typedef int_t<25> int25;
typedef int_t<26> int26;
typedef int_t<27> int27;
typedef int_t<28> int28;
typedef int_t<29> int29;
typedef int_t<30> int30;
typedef int_t<31> int31;
typedef int32_t int32;
typedef int64_t int64;
typedef uint_t< 1> uint1;
typedef uint_t< 2> uint2;
typedef uint_t< 3> uint3;
typedef uint_t< 4> uint4;
typedef uint_t< 5> uint5;
typedef uint_t< 6> uint6;
typedef uint_t< 7> uint7;
typedef uint8_t uint8;
typedef uint_t< 9> uint9;
typedef uint_t<10> uint10;
typedef uint_t<11> uint11;
typedef uint_t<12> uint12;
typedef uint_t<13> uint13;
typedef uint_t<14> uint14;
typedef uint_t<15> uint15;
typedef uint16_t uint16;
typedef uint_t<17> uint17;
typedef uint_t<18> uint18;
typedef uint_t<19> uint19;
typedef uint_t<20> uint20;
typedef uint_t<21> uint21;
typedef uint_t<22> uint22;
typedef uint_t<23> uint23;
typedef uint_t<24> uint24;
typedef uint_t<25> uint25;
typedef uint_t<26> uint26;
typedef uint_t<27> uint27;
typedef uint_t<28> uint28;
typedef uint_t<29> uint29;
typedef uint_t<30> uint30;
typedef uint_t<31> uint31;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef varuint_t varuint;
#endif

View File

@ -1,3 +1,5 @@
options += gameboy
gameboy_objects := gameboy-interface gameboy-system gameboy-scheduler gameboy_objects := gameboy-interface gameboy-system gameboy-scheduler
gameboy_objects += gameboy-memory gameboy-cartridge gameboy_objects += gameboy-memory gameboy-cartridge
gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd

View File

@ -1,6 +1,8 @@
#ifndef GAMEBOY_HPP #ifndef GAMEBOY_HPP
#define GAMEBOY_HPP #define GAMEBOY_HPP
#include <base/base.hpp>
namespace GameBoy { namespace GameBoy {
namespace Info { namespace Info {
static const char Name[] = "bgameboy"; static const char Name[] = "bgameboy";
@ -16,59 +18,9 @@ namespace GameBoy {
*/ */
#include <libco/libco.h> #include <libco/libco.h>
#include <nall/gameboy/cartridge.hpp>
#include <nall/platform.hpp>
#include <nall/property.hpp>
#include <nall/random.hpp>
#include <nall/serializer.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/varint.hpp>
using namespace nall;
namespace GameBoy { namespace GameBoy {
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint_t< 1> uint1;
typedef uint_t< 2> uint2;
typedef uint_t< 3> uint3;
typedef uint_t< 4> uint4;
typedef uint_t< 5> uint5;
typedef uint_t< 6> uint6;
typedef uint_t< 7> uint7;
typedef uint_t< 9> uint9;
typedef uint_t<10> uint10;
typedef uint_t<11> uint11;
typedef uint_t<12> uint12;
typedef uint_t<13> uint13;
typedef uint_t<14> uint14;
typedef uint_t<15> uint15;
typedef uint_t<17> uint17;
typedef uint_t<18> uint18;
typedef uint_t<19> uint19;
typedef uint_t<20> uint20;
typedef uint_t<21> uint21;
typedef uint_t<22> uint22;
typedef uint_t<23> uint23;
typedef uint_t<24> uint24;
typedef uint_t<25> uint25;
typedef uint_t<26> uint26;
typedef uint_t<27> uint27;
typedef uint_t<28> uint28;
typedef uint_t<29> uint29;
typedef uint_t<30> uint30;
typedef uint_t<31> uint31;
struct Processor { struct Processor {
cothread_t thread; cothread_t thread;
unsigned frequency; unsigned frequency;

View File

@ -55,10 +55,10 @@ namespace nall {
template<typename T> void integer(T &value) { template<typename T> void integer(T &value) {
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) }; enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
if(imode == Save) { if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = value >> (n << 3); for(unsigned n = 0; n < size; n++) idata[isize++] = (uintmax_t)value >> (n << 3);
} else if(imode == Load) { } else if(imode == Load) {
value = 0; value = 0;
for(unsigned n = 0; n < size; n++) value |= idata[isize++] << (n << 3); for(unsigned n = 0; n < size; n++) value |= (uintmax_t)idata[isize++] << (n << 3);
} else if(imode == Size) { } else if(imode == Size) {
isize += size; isize += size;
} }

View File

@ -1,6 +1,8 @@
#ifndef NES_HPP #ifndef NES_HPP
#define NES_HPP #define NES_HPP
#include <base/base.hpp>
namespace NES { namespace NES {
namespace Info { namespace Info {
static const char Name[] = "bnes"; static const char Name[] = "bnes";
@ -17,66 +19,7 @@ namespace NES {
#include <libco/libco.h> #include <libco/libco.h>
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>
#include <nall/array.hpp>
#include <nall/crc32.hpp>
#include <nall/dl.hpp>
#include <nall/endian.hpp>
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/property.hpp>
#include <nall/serializer.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>
using namespace nall;
namespace NES { namespace NES {
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint_t< 1> uint1;
typedef uint_t< 2> uint2;
typedef uint_t< 3> uint3;
typedef uint_t< 4> uint4;
typedef uint_t< 5> uint5;
typedef uint_t< 6> uint6;
typedef uint_t< 7> uint7;
typedef uint8_t uint8;
typedef uint_t< 9> uint9;
typedef uint_t<10> uint10;
typedef uint_t<11> uint11;
typedef uint_t<12> uint12;
typedef uint_t<13> uint13;
typedef uint_t<14> uint14;
typedef uint_t<15> uint15;
typedef uint16_t uint16;
typedef uint_t<17> uint17;
typedef uint_t<18> uint18;
typedef uint_t<19> uint19;
typedef uint_t<20> uint20;
typedef uint_t<21> uint21;
typedef uint_t<22> uint22;
typedef uint_t<23> uint23;
typedef uint_t<24> uint24;
typedef uint_t<25> uint25;
typedef uint_t<26> uint26;
typedef uint_t<27> uint27;
typedef uint_t<28> uint28;
typedef uint_t<29> uint29;
typedef uint_t<30> uint30;
typedef uint_t<31> uint31;
typedef uint32_t uint32;
typedef uint64_t uint64;
struct Processor { struct Processor {
cothread_t thread; cothread_t thread;
unsigned frequency; unsigned frequency;

View File

@ -2,7 +2,7 @@ snes_objects := snes-interface snes-system snes-controller
snes_objects += snes-cartridge snes-cheat snes_objects += snes-cartridge snes-cheat
snes_objects += snes-memory snes-cpucore snes-smpcore snes_objects += snes-memory snes-cpucore snes-smpcore
snes_objects += snes-cpu snes-smp snes-dsp snes-ppu snes_objects += snes-cpu snes-smp snes-dsp snes-ppu
snes_objects += snes-nss snes-icd2 snes-superfx snes-sa1 snes-necdsp snes-hitachidsp snes_objects += snes-icd2 snes-nss snes-superfx snes-sa1 snes-necdsp snes-hitachidsp
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110
snes_objects += snes-obc1 snes-st0018 snes-sufamiturbo snes_objects += snes-obc1 snes-st0018 snes-sufamiturbo
snes_objects += snes-msu1 snes-link snes_objects += snes-msu1 snes-link

View File

@ -1,10 +1,10 @@
uint16 get_vram_address(); uint16 get_vram_address();
debugvirtual uint8 vram_mmio_read(uint16 addr); uint8 vram_mmio_read(uint16 addr);
debugvirtual void vram_mmio_write(uint16 addr, uint8 data); void vram_mmio_write(uint16 addr, uint8 data);
debugvirtual uint8 oam_mmio_read(uint16 addr); uint8 oam_mmio_read(uint16 addr);
debugvirtual void oam_mmio_write(uint16 addr, uint8 data); void oam_mmio_write(uint16 addr, uint8 data);
debugvirtual uint8 cgram_mmio_read(uint16 addr); uint8 cgram_mmio_read(uint16 addr);
debugvirtual void cgram_mmio_write(uint16 addr, uint8 data); void cgram_mmio_write(uint16 addr, uint8 data);

View File

@ -58,7 +58,11 @@ void Cartridge::load(Mode cartridge_mode, const char *markup) {
sha256 = nall::sha256(sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size()); sha256 = nall::sha256(sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size());
break; break;
case Mode::SuperGameBoy: case Mode::SuperGameBoy:
#if defined(GAMEBOY)
sha256 = GameBoy::cartridge.sha256(); sha256 = GameBoy::cartridge.sha256();
#else
throw "Game Boy support not present";
#endif
break; break;
} }

View File

@ -106,6 +106,7 @@ void Cartridge::parse_markup_nss(XML::Node &root) {
} }
void Cartridge::parse_markup_icd2(XML::Node &root) { void Cartridge::parse_markup_icd2(XML::Node &root) {
#if defined(GAMEBOY)
if(root.exists() == false) return; if(root.exists() == false) return;
if(mode != Mode::SuperGameBoy) return; if(mode != Mode::SuperGameBoy) return;
@ -117,6 +118,7 @@ void Cartridge::parse_markup_icd2(XML::Node &root) {
parse_markup_map(m, node); parse_markup_map(m, node);
mapping.append(m); mapping.append(m);
} }
#endif
} }
void Cartridge::parse_markup_superfx(XML::Node &root) { void Cartridge::parse_markup_superfx(XML::Node &root) {

View File

@ -45,44 +45,42 @@ void BSXCartridge::memory_write(Memory &memory, unsigned addr, uint8 data) {
//mcu_access() allows mcu_read() and mcu_write() to share decoding logic //mcu_access() allows mcu_read() and mcu_write() to share decoding logic
uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) { uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) {
if(within<0x00, 0x1f, 0x8000, 0xffff>(addr)) { if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
if(r07 == 1) { if(r07 == 1) {
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff); addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
return memory_access(write, cartridge.rom, addr, data); return memory_access(write, cartridge.rom, addr, data);
} }
} }
if(within<0x80, 0x9f, 0x8000, 0xffff>(addr)) { if((addr & 0xe08000) == 0x808000) { //$80-9f:8000-ffff
if(r08 == 1) { if(r08 == 1) {
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff); addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
return memory_access(write, cartridge.rom, addr, data); return memory_access(write, cartridge.rom, addr, data);
} }
} }
if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) { if((addr & 0xe0e000) == 0x206000) { //$20-3f:6000-7fff
return memory_access(write, psram, addr, data); return memory_access(write, psram, addr, data);
} }
if(within<0x40, 0x4f, 0x0000, 0xffff>(addr)) { if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
if(r05 == 0) return memory_access(write, psram, addr & 0x0fffff, data); if(r05 == 0) return memory_access(write, psram, addr & 0x0fffff, data);
} }
if(within<0x50, 0x5f, 0x0000, 0xffff>(addr)) { if((addr & 0xf00000) == 0x500000) { //$50-5f:0000-ffff
if(r06 == 0) return memory_access(write, psram, addr & 0x0fffff, data); if(r06 == 0) return memory_access(write, psram, addr & 0x0fffff, data);
} }
if(within<0x60, 0x6f, 0x0000, 0xffff>(addr)) { if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
if(r03 == 1) return memory_access(write, psram, addr & 0x0fffff, data); if(r03 == 1) return memory_access(write, psram, addr & 0x0fffff, data);
} }
if(within<0x70, 0x77, 0x0000, 0xffff>(addr)) { if((addr & 0xf80000) == 0x700000) { //$70-77:0000-ffff
return memory_access(write, psram, addr & 0x07ffff, data); return memory_access(write, psram, addr & 0x07ffff, data);
} }
if(within<0x00, 0x3f, 0x8000, 0xffff>(addr) if(((addr & 0x408000) == 0x008000) //$00-3f|80-bf:8000-ffff
|| within<0x40, 0x7f, 0x0000, 0xffff>(addr) || ((addr & 0x400000) == 0x400000) //$40-7f|c0-ff:0000-ffff
|| within<0x80, 0xbf, 0x8000, 0xffff>(addr)
|| within<0xc0, 0xff, 0x0000, 0xffff>(addr)
) { ) {
if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff); if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
Memory &memory = (r01 == 0 ? (Memory&)bsxflash : (Memory&)psram); Memory &memory = (r01 == 0 ? (Memory&)bsxflash : (Memory&)psram);
@ -101,12 +99,12 @@ void BSXCartridge::mcu_write(unsigned addr, uint8 data) {
} }
uint8 BSXCartridge::mmio_read(unsigned addr) { uint8 BSXCartridge::mmio_read(unsigned addr) {
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) { if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
uint8 n = (addr >> 16) & 15; uint8 n = (addr >> 16) & 15;
return r[n]; return r[n];
} }
if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) { if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
return memory_read(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff)); return memory_read(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
} }
@ -114,14 +112,14 @@ uint8 BSXCartridge::mmio_read(unsigned addr) {
} }
void BSXCartridge::mmio_write(unsigned addr, uint8 data) { void BSXCartridge::mmio_write(unsigned addr, uint8 data) {
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) { if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
uint8 n = (addr >> 16) & 15; uint8 n = (addr >> 16) & 15;
r[n] = data; r[n] = data;
if(n == 0x0e && data & 0x80) mmio_commit(); if(n == 0x0e && data & 0x80) mmio_commit();
return; return;
} }
if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) { if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
return memory_write(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data); return memory_write(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
} }
} }

View File

@ -3,8 +3,11 @@ struct Coprocessor : Processor {
alwaysinline void synchronize_cpu(); alwaysinline void synchronize_cpu();
}; };
#if defined(GAMEBOY)
#include <snes/chip/icd2/icd2.hpp>
#endif
#include <snes/chip/nss/nss.hpp> #include <snes/chip/nss/nss.hpp>
#include <snes/chip/icd2/icd2.hpp>
#include <snes/chip/superfx/superfx.hpp> #include <snes/chip/superfx/superfx.hpp>
#include <snes/chip/sa1/sa1.hpp> #include <snes/chip/sa1/sa1.hpp>
#include <snes/chip/necdsp/necdsp.hpp> #include <snes/chip/necdsp/necdsp.hpp>

View File

@ -1,3 +1,5 @@
#if defined(GAMEBOY)
#include <snes/snes.hpp> #include <snes/snes.hpp>
#define ICD2_CPP #define ICD2_CPP
@ -73,3 +75,5 @@ void ICD2::reset() {
} }
} }
#endif

View File

@ -83,6 +83,8 @@ void CPU::enter() {
} }
void CPU::op_step() { void CPU::op_step() {
debugger.op_exec(regs.pc.d);
(this->*opcode_table[op_readpc()])(); (this->*opcode_table[op_readpc()])();
} }

View File

@ -133,6 +133,13 @@ private:
static void Enter(); static void Enter();
void op_step(); void op_step();
public:
struct Debugger {
hook<void (uint32)> op_exec;
hook<void (uint32)> op_read;
hook<void (uint32, uint8)> op_write;
} debugger;
}; };
extern CPU cpu; extern CPU cpu;

View File

@ -11,6 +11,8 @@ void CPU::op_io() {
} }
uint8 CPU::op_read(uint32 addr) { uint8 CPU::op_read(uint32 addr) {
debugger.op_read(addr);
status.clock_count = speed(addr); status.clock_count = speed(addr);
dma_edge(); dma_edge();
add_clocks(status.clock_count - 4); add_clocks(status.clock_count - 4);
@ -21,6 +23,8 @@ uint8 CPU::op_read(uint32 addr) {
} }
void CPU::op_write(uint32 addr, uint8 data) { void CPU::op_write(uint32 addr, uint8 data) {
debugger.op_write(addr, data);
alu_edge(); alu_edge();
status.clock_count = speed(addr); status.clock_count = speed(addr);
dma_edge(); dma_edge();

View File

@ -1,6 +1,8 @@
#ifndef SNES_HPP #ifndef SNES_HPP
#define SNES_HPP #define SNES_HPP
#include <base/base.hpp>
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
@ -17,84 +19,11 @@ namespace SNES {
#include <libco/libco.h> #include <libco/libco.h>
#include <nall/platform.hpp> #if defined(GAMEBOY)
#include <nall/algorithm.hpp> #include <gameboy/gameboy.hpp>
#include <nall/any.hpp> #endif
#include <nall/array.hpp>
#include <nall/dl.hpp>
#include <nall/dsp.hpp>
#include <nall/endian.hpp>
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/moduloarray.hpp>
#include <nall/priorityqueue.hpp>
#include <nall/property.hpp>
#include <nall/serializer.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>
#include <nall/gameboy/cartridge.hpp>
using namespace nall;
#include <gameboy/gameboy.hpp>
namespace SNES { namespace SNES {
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef int_t<24> int24;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint_t< 1> uint1;
typedef uint_t< 2> uint2;
typedef uint_t< 3> uint3;
typedef uint_t< 4> uint4;
typedef uint_t< 5> uint5;
typedef uint_t< 6> uint6;
typedef uint_t< 7> uint7;
typedef uint_t< 9> uint9;
typedef uint_t<10> uint10;
typedef uint_t<11> uint11;
typedef uint_t<12> uint12;
typedef uint_t<13> uint13;
typedef uint_t<14> uint14;
typedef uint_t<15> uint15;
typedef uint_t<17> uint17;
typedef uint_t<18> uint18;
typedef uint_t<19> uint19;
typedef uint_t<20> uint20;
typedef uint_t<21> uint21;
typedef uint_t<22> uint22;
typedef uint_t<23> uint23;
typedef uint_t<24> uint24;
typedef uint_t<25> uint25;
typedef uint_t<26> uint26;
typedef uint_t<27> uint27;
typedef uint_t<28> uint28;
typedef uint_t<29> uint29;
typedef uint_t<30> uint30;
typedef uint_t<31> uint31;
typedef varuint_t varuint;
template<uint8 banklo, uint8 bankhi, uint16 addrlo, uint16 addrhi>
alwaysinline bool within(unsigned addr) {
static const unsigned lo = (banklo << 16) | addrlo;
static const unsigned hi = (bankhi << 16) | addrhi;
static const unsigned mask = ~(hi ^ lo);
return (addr & mask) == lo;
}
struct Processor { struct Processor {
cothread_t thread; cothread_t thread;
unsigned frequency; unsigned frequency;

View File

@ -58,7 +58,9 @@ void System::serialize_all(serializer &s) {
dsp.serialize(s); dsp.serialize(s);
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s); if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s);
#if defined(GAMEBOY)
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s); if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s);
#endif
if(cartridge.has_superfx()) superfx.serialize(s); if(cartridge.has_superfx()) superfx.serialize(s);
if(cartridge.has_sa1()) sa1.serialize(s); if(cartridge.has_sa1()) sa1.serialize(s);
if(cartridge.has_necdsp()) necdsp.serialize(s); if(cartridge.has_necdsp()) necdsp.serialize(s);

View File

@ -65,7 +65,9 @@ void System::runthreadtosave() {
void System::init() { void System::init() {
assert(interface != 0); assert(interface != 0);
#if defined(GAMEBOY)
icd2.init(); icd2.init();
#endif
nss.init(); nss.init();
superfx.init(); superfx.init();
sa1.init(); sa1.init();
@ -104,7 +106,9 @@ void System::load() {
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.load(); if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.load();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.load(); if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.load();
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.load(); if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.load();
#if defined(GAMEBOY)
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.load(); if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.load();
#endif
if(cartridge.has_bsx_slot()) bsxflash.load(); if(cartridge.has_bsx_slot()) bsxflash.load();
if(cartridge.has_nss_dip()) nss.load(); if(cartridge.has_nss_dip()) nss.load();
@ -128,7 +132,9 @@ void System::unload() {
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.unload(); if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.unload();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.unload(); if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.unload();
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.unload(); if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.unload();
#if defined(GAMEBOY)
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.unload(); if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.unload();
#endif
if(cartridge.has_bsx_slot()) bsxflash.unload(); if(cartridge.has_bsx_slot()) bsxflash.unload();
if(cartridge.has_nss_dip()) nss.unload(); if(cartridge.has_nss_dip()) nss.unload();
@ -164,7 +170,9 @@ void System::power() {
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.power(); if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.power();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.power(); if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.power();
#if defined(GAMEBOY)
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.power(); if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.power();
#endif
if(cartridge.has_bsx_slot()) bsxflash.power(); if(cartridge.has_bsx_slot()) bsxflash.power();
if(cartridge.has_nss_dip()) nss.power(); if(cartridge.has_nss_dip()) nss.power();
@ -192,7 +200,9 @@ void System::reset() {
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.reset(); if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.reset();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.reset(); if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.reset();
#if defined(GAMEBOY)
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.reset(); if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.reset();
#endif
if(cartridge.has_bsx_slot()) bsxflash.reset(); if(cartridge.has_bsx_slot()) bsxflash.reset();
if(cartridge.has_nss_dip()) nss.reset(); if(cartridge.has_nss_dip()) nss.reset();
@ -208,7 +218,9 @@ void System::reset() {
if(cartridge.has_msu1()) msu1.reset(); if(cartridge.has_msu1()) msu1.reset();
if(cartridge.has_link()) link.reset(); if(cartridge.has_link()) link.reset();
#if defined(GAMEBOY)
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2); if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2);
#endif
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx); if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1); if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp); if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp);

68
bsnes/ui-debugger/Makefile Executable file
View File

@ -0,0 +1,68 @@
include $(snes)/Makefile
name := bsnes-debugger
ui_objects := ui-main ui-interface ui-console ui-video
ui_objects += phoenix ruby
ui_objects += $(if $(call streq,$(platform),win),resource)
# platform
ifeq ($(platform),x)
ruby := audio.alsa
else ifeq ($(platform),osx)
ruby := audio.openal
else ifeq ($(platform),win)
ruby := audio.xaudio2
endif
# phoenix
include phoenix/Makefile
link += $(phoenixlink)
# ruby
include ruby/Makefile
link += $(rubylink)
# rules
objects := $(ui_objects) $(objects)
objects := $(patsubst %,obj/%.o,$(objects))
obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/)
obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/*)
obj/ui-console.o: $(ui)/console/console.cpp $(call rwildcard,$(ui)/*)
obj/ui-video.o: $(ui)/video/video.cpp $(call rwildcard,$(ui)/*)
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
$(call compile,$(rubyflags))
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
$(call compile,$(phoenixflags))
obj/resource.o: $(ui)/resource.rc
# windres --target=pe-i386 $(ui)/resource.rc obj/resource.o
windres $(ui)/resource.rc obj/resource.o
# targets
build: $(objects)
ifeq ($(platform),osx)
test -d ../$(name).app || mkdir -p ../$(name).app/Contents/MacOS
$(strip $(cpp) -o ../$(name).app/Contents/MacOS/$(name) $(objects) $(link))
else
$(strip $(cpp) -o out/$(name) $(objects) $(link))
endif
install:
ifeq ($(platform),x)
install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name)
mkdir -p ~/.config/$(name)
install -D -m 644 data/$(name).png $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop
cp data/cheats.xml ~/.config/$(name)/cheats.xml
chmod 777 ~/.config/$(name) ~/.config/$(name)/cheats.xml
endif
uninstall:
ifeq ($(platform),x)
rm $(DESTDIR)$(prefix)/bin/$(name)
rm $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
rm $(DESTDIR)$(prefix)/share/applications/$(name).desktop
endif

39
bsnes/ui-debugger/base.hpp Executable file
View File

@ -0,0 +1,39 @@
#if !defined(PROFILE_ACCURACY)
#error "debugger is only compatible with accuracy profile"
#endif
#include <snes/snes.hpp>
#include <nall/config.hpp>
#include <nall/directory.hpp>
#include <nall/dsp.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/snes/cartridge.hpp>
using namespace nall;
#include <phoenix/phoenix.hpp>
using namespace phoenix;
#include <ruby/ruby.hpp>
using namespace ruby;
#include "interface/interface.hpp"
#include "console/console.hpp"
#include "video/video.hpp"
struct Application {
bool quit;
string basepath;
string userpath;
string proportionalFont;
string proportionalFontBold;
string monospaceFont;
Application(int argc, char **argv);
~Application();
};
extern Application *application;

View File

@ -0,0 +1,67 @@
#include "../base.hpp"
ConsoleWindow *consoleWindow = nullptr;
ConsoleWindow::ConsoleWindow() {
setTitle({"Console - bsnes v", Version});
setGeometry({64, 650, 800, 400});
setMenuVisible();
menuEmulation.setText("&Emulation");
menuEmulationReloadCartridge.setText("Reload Cartridge");
menuEmulationPowerCycle.setText("Power Cycle");
menuEmulationReset.setText("Reset");
menuEmulationSynchronizeAudio.setText("Synchronize Audio");
menuEmulationSynchronizeAudio.setChecked();
menuEmulationMuteAudio.setText("Mute Audio");
menuEmulation.append(menuEmulationReloadCartridge, menuEmulationPowerCycle, menuEmulationReset,
menuEmulationSeparator, menuEmulationSynchronizeAudio, menuEmulationMuteAudio);
append(menuEmulation);
menuWindows.setText("&Windows");
menuWindowsVideo.setText("Video");
menuWindows.append(menuWindowsVideo);
append(menuWindows);
layout.setMargin(5);
runButton.setText("Run");
stepButton.setText("Step");
console.setFont(application->monospaceFont);
layout.append(commandLayout, {~0, 0}, 5);
commandLayout.append(runButton, {80, ~0}, 5);
commandLayout.append(stepButton, {80, ~0});
layout.append(console, {~0, ~0});
append(layout);
onClose = [] { application->quit = true; };
menuEmulationReloadCartridge.onActivate = [&] {
interface->loadCartridge(interface->fileName);
};
menuEmulationPowerCycle.onActivate = [&] {
SNES::system.power();
print("System power cycled\n");
};
menuEmulationReset.onActivate = [&] {
SNES::system.reset();
print("System reset\n");
};
menuEmulationSynchronizeAudio.onToggle = [&] {
audio.set(Audio::Synchronize, menuEmulationSynchronizeAudio.checked());
};
menuWindowsVideo.onActivate = [&] {
videoWindow->setVisible();
videoWindow->setFocused();
};
}
void ConsoleWindow::print(const string &text) {
string output = console.text();
output.append(text);
console.setText(output);
console.setCursorPosition(~0);
}

View File

@ -0,0 +1,24 @@
struct ConsoleWindow : Window {
Menu menuEmulation;
Item menuEmulationReloadCartridge;
Item menuEmulationPowerCycle;
Item menuEmulationReset;
Separator menuEmulationSeparator;
CheckItem menuEmulationSynchronizeAudio;
CheckItem menuEmulationMuteAudio;
Menu menuWindows;
Item menuWindowsVideo;
VerticalLayout layout;
HorizontalLayout commandLayout;
Button runButton;
Button stepButton;
TextEdit console;
void print(const string &text);
ConsoleWindow();
};
extern ConsoleWindow *consoleWindow;

View File

@ -0,0 +1,127 @@
#include "../base.hpp"
Interface *interface = nullptr;
bool Interface::loadCartridge(const string &filename) {
uint8_t *data;
unsigned size;
if(file::read(filename, data, size) == false) return false;
if(SNES::cartridge.loaded()) {
saveMemory();
SNES::cartridge.unload();
consoleWindow->print("Cartridge unloaded\n");
}
fileName = filename;
baseName = nall::basename(fileName);
string markup;
markup.readfile({ baseName, ".xml" });
if(markup.empty()) markup = SnesCartridge(data, size).markup;
SNES::cartridge.rom.copy(data, size);
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, markup);
SNES::system.power();
delete[] data;
videoWindow->setTitle(notdir(baseName));
SNES::video.generate(SNES::Video::Format::RGB24);
consoleWindow->print({"Loaded ", fileName, "\n", markup, "\n"});
loadMemory();
return true;
}
void Interface::loadMemory() {
for(auto &memory : SNES::cartridge.nvram) {
if(memory.size == 0) continue;
string filename = { baseName, memory.id };
uint8_t *data;
unsigned size;
if(file::read(filename, data, size)) {
consoleWindow->print({"Loaded ", filename, "\n"});
memcpy(memory.data, data, min(memory.size, size));
delete[] data;
}
}
}
void Interface::saveMemory() {
for(auto &memory : SNES::cartridge.nvram) {
if(memory.size == 0) continue;
string filename = { baseName, memory.id };
if(file::write(filename, memory.data, memory.size)) {
consoleWindow->print({"Saved ", filename, "\n"});
}
}
}
//hires is always true for accuracy core
//overscan is ignored for the debugger port
void Interface::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) {
uint32_t *output = videoWindow->canvas.data();
if(interlace == false) {
for(unsigned y = 0; y < 240; y++) {
const uint32_t *sp = data + y * 1024;
uint32_t *dp0 = output + y * 1024, *dp1 = dp0 + 512;
for(unsigned x = 0; x < 512; x++) {
*dp0++ = SNES::video.palette[*sp];
*dp1++ = SNES::video.palette[*sp++];
}
}
} else {
for(unsigned y = 0; y < 480; y++) {
const uint32_t *sp = data + y * 512;
uint32_t *dp = output + y * 512;
for(unsigned x = 0; x < 512; x++) {
*dp++ = SNES::video.palette[*sp++];
}
}
}
videoWindow->canvas.update();
}
void Interface::audioSample(int16_t lsample, int16_t rsample) {
if(consoleWindow->menuEmulationMuteAudio.checked()) lsample = rsample = 0;
audio.sample(lsample, rsample);
}
int16_t Interface::inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
if(videoWindow->focused() == false) return 0;
auto keyboardState = phoenix::Keyboard::state();
if(port == 0) {
if(device == SNES::Input::Device::Joypad) {
switch((SNES::Input::JoypadID)id) {
case SNES::Input::JoypadID::Up: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::Up];
case SNES::Input::JoypadID::Down: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::Down];
case SNES::Input::JoypadID::Left: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::Left];
case SNES::Input::JoypadID::Right: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::Right];
case SNES::Input::JoypadID::B: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::B];
case SNES::Input::JoypadID::A: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::A];
case SNES::Input::JoypadID::Y: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::Y];
case SNES::Input::JoypadID::X: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::X];
case SNES::Input::JoypadID::L: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::L];
case SNES::Input::JoypadID::R: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::R];
case SNES::Input::JoypadID::Select: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::Apostrophe];
case SNES::Input::JoypadID::Start: return keyboardState[(unsigned)phoenix::Keyboard::Scancode::Return];
}
}
}
return 0;
}
string Interface::path(SNES::Cartridge::Slot slot, const string &hint) {
return { baseName, hint };
}
void Interface::message(const string &text) {
consoleWindow->print({text, "\n"});
}
Interface::Interface() {
SNES::interface = this;
SNES::system.init();
}

View File

@ -0,0 +1,19 @@
struct Interface : SNES::Interface {
string fileName;
string baseName;
bool loadCartridge(const string &filename);
void loadMemory();
void saveMemory();
void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan);
void audioSample(int16_t lsample, int16_t rsample);
int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id);
string path(SNES::Cartridge::Slot slot, const string &hint);
void message(const string &text);
Interface();
};
extern Interface *interface;

73
bsnes/ui-debugger/main.cpp Executable file
View File

@ -0,0 +1,73 @@
#include "base.hpp"
Application *application = nullptr;
Application::Application(int argc, char **argv) {
application = this;
quit = false;
{
char path[PATH_MAX];
auto unused = ::realpath(argv[0], path);
basepath = dir(path);
unused = ::userpath(path);
userpath = path;
if(Intrinsics::platform() == Intrinsics::Platform::Windows) {
userpath.append("bsnes/");
} else {
userpath.append(".config/bsnes/");
}
mkdir(userpath, 0755);
}
if(Intrinsics::platform() == Intrinsics::Platform::Windows) {
proportionalFont = "Tahoma, 8";
proportionalFontBold = "Tahoma, 8, Bold";
monospaceFont = "Lucida Console, 8";
} else {
proportionalFont = "Sans, 8";
proportionalFontBold = "Sans, 8, Bold";
monospaceFont = "Liberation Mono, 8";
}
string filename;
if(argc >= 2) filename = argv[1];
if(!file::exists(filename)) filename = "/media/sdb1/root/cartridges/SNES - Archived/zelda_us.sfc";
if(!file::exists(filename)) filename = DialogWindow::fileOpen(Window::None, "", "SNES images (*.sfc)");
if(!file::exists(filename)) return;
interface = new Interface;
consoleWindow = new ConsoleWindow;
videoWindow = new VideoWindow;
videoWindow->setVisible();
consoleWindow->setVisible();
if(audio.init() == false) {
audio.driver("None");
audio.init();
}
audio.set(Audio::Synchronize, true);
audio.set(Audio::Frequency, 32000u);
if(interface->loadCartridge(filename) == false) return;
while(quit == false) {
OS::processEvents();
SNES::system.run();
}
interface->saveMemory();
}
Application::~Application() {
delete videoWindow;
delete consoleWindow;
delete interface;
}
int main(int argc, char **argv) {
new Application(argc, argv);
delete application;
return 0;
}

View File

@ -0,0 +1,29 @@
#include "../base.hpp"
VideoWindow *videoWindow = nullptr;
VideoWindow::VideoWindow() {
setTitle("Video");
setGeometry({64, 64, 512, 480});
setResizable(false);
setStatusFont(application->proportionalFontBold);
setStatusVisible();
canvas.setSize({512, 480});
layout.append(canvas, {~0, ~0});
append(layout);
canvas.onMouseLeave = [&] {
setStatusText("");
};
canvas.onMouseMove = [&](Position position) {
uint32_t color = canvas.data()[position.y * 512 + position.x];
unsigned r = (color >> 19) & 31, g = (color >> 11) & 31, b = (color >> 3) & 31;
setStatusText({
decimal(position.x / 2), ".", decimal((position.x & 1) * 5), ", ",
decimal(position.y / 2), ".", decimal((position.y & 1) * 5), ", ",
"0x", hex<4>((b << 10) + (g << 5) + (r << 0))
});
};
}

View File

@ -0,0 +1,8 @@
struct VideoWindow : Window {
VerticalLayout layout;
Canvas canvas;
VideoWindow();
};
extern VideoWindow *videoWindow;

View File

@ -79,7 +79,8 @@ struct Interface : public SNES::Interface {
static Interface interface; static Interface interface;
const char* snes_library_id(void) { const char* snes_library_id(void) {
return "bsnes v085"; static string version = {"bsnes v", Version};
return version;
} }
unsigned snes_library_revision_major(void) { unsigned snes_library_revision_major(void) {

View File

@ -1,6 +1,6 @@
include $(nes)/Makefile include $(nes)/Makefile
include $(snes)/Makefile
include $(gameboy)/Makefile include $(gameboy)/Makefile
include $(snes)/Makefile
name := bsnes name := bsnes
ui_objects := ui-main ui-config ui-interface ui-input ui-utility ui_objects := ui-main ui-config ui-interface ui-input ui-utility

View File

@ -1,6 +1,6 @@
#include <nes/nes.hpp> #include <nes/nes.hpp>
#include <snes/snes.hpp>
#include <gameboy/gameboy.hpp> #include <gameboy/gameboy.hpp>
#include <snes/snes.hpp>
#include <nall/compositor.hpp> #include <nall/compositor.hpp>
#include <nall/config.hpp> #include <nall/config.hpp>

View File

@ -1,6 +1,6 @@
#include "base.hpp" #include "base.hpp"
Application *application = 0; Application *application = nullptr;
nall::DSP dspaudio; nall::DSP dspaudio;
//allow files to exist in the same folder as binary; //allow files to exist in the same folder as binary;
@ -27,7 +27,7 @@ void Application::run() {
} }
Application::Application(int argc, char **argv) { Application::Application(int argc, char **argv) {
title = "bsnes v085.03"; title = {"bsnes v", Version};
application = this; application = this;
quit = false; quit = false;