mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
892bb3ab01
commit
730e6ae4cc
|
@ -4,10 +4,10 @@ nes := nes
|
|||
snes := snes
|
||||
gameboy := gameboy
|
||||
profile := accuracy
|
||||
ui := ui
|
||||
ui := ui-debugger
|
||||
|
||||
# options += console
|
||||
# options += debugger
|
||||
options += debugger
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
|
@ -39,8 +39,6 @@ else
|
|||
unknown_platform: help;
|
||||
endif
|
||||
|
||||
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
|
||||
|
||||
# implicit rules
|
||||
compile = \
|
||||
$(strip \
|
||||
|
@ -59,6 +57,7 @@ all: build;
|
|||
obj/libco.o: libco/libco.c libco/*
|
||||
|
||||
include $(ui)/Makefile
|
||||
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
|
||||
|
||||
# targets
|
||||
clean:
|
||||
|
@ -91,6 +90,6 @@ sync:
|
|||
rm -r phoenix/test
|
||||
|
||||
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:;
|
||||
|
|
|
@ -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
|
|
@ -1,3 +1,5 @@
|
|||
options += gameboy
|
||||
|
||||
gameboy_objects := gameboy-interface gameboy-system gameboy-scheduler
|
||||
gameboy_objects += gameboy-memory gameboy-cartridge
|
||||
gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef GAMEBOY_HPP
|
||||
#define GAMEBOY_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
|
||||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
|
@ -16,59 +18,9 @@ namespace GameBoy {
|
|||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
#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;
|
||||
#include <nall/gameboy/cartridge.hpp>
|
||||
|
||||
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 {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
|
|
|
@ -55,10 +55,10 @@ namespace nall {
|
|||
template<typename T> void integer(T &value) {
|
||||
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
|
||||
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) {
|
||||
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) {
|
||||
isize += size;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef NES_HPP
|
||||
#define NES_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bnes";
|
||||
|
@ -17,66 +19,7 @@ namespace NES {
|
|||
|
||||
#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 {
|
||||
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 {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
|
|
|
@ -2,7 +2,7 @@ snes_objects := snes-interface snes-system snes-controller
|
|||
snes_objects += snes-cartridge snes-cheat
|
||||
snes_objects += snes-memory snes-cpucore snes-smpcore
|
||||
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-obc1 snes-st0018 snes-sufamiturbo
|
||||
snes_objects += snes-msu1 snes-link
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
uint16 get_vram_address();
|
||||
|
||||
debugvirtual uint8 vram_mmio_read(uint16 addr);
|
||||
debugvirtual void vram_mmio_write(uint16 addr, uint8 data);
|
||||
uint8 vram_mmio_read(uint16 addr);
|
||||
void vram_mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
debugvirtual uint8 oam_mmio_read(uint16 addr);
|
||||
debugvirtual void oam_mmio_write(uint16 addr, uint8 data);
|
||||
uint8 oam_mmio_read(uint16 addr);
|
||||
void oam_mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
debugvirtual uint8 cgram_mmio_read(uint16 addr);
|
||||
debugvirtual void cgram_mmio_write(uint16 addr, uint8 data);
|
||||
uint8 cgram_mmio_read(uint16 addr);
|
||||
void cgram_mmio_write(uint16 addr, uint8 data);
|
||||
|
|
|
@ -58,7 +58,11 @@ void Cartridge::load(Mode cartridge_mode, const char *markup) {
|
|||
sha256 = nall::sha256(sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size());
|
||||
break;
|
||||
case Mode::SuperGameBoy:
|
||||
#if defined(GAMEBOY)
|
||||
sha256 = GameBoy::cartridge.sha256();
|
||||
#else
|
||||
throw "Game Boy support not present";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ void Cartridge::parse_markup_nss(XML::Node &root) {
|
|||
}
|
||||
|
||||
void Cartridge::parse_markup_icd2(XML::Node &root) {
|
||||
#if defined(GAMEBOY)
|
||||
if(root.exists() == false) return;
|
||||
if(mode != Mode::SuperGameBoy) return;
|
||||
|
||||
|
@ -117,6 +118,7 @@ void Cartridge::parse_markup_icd2(XML::Node &root) {
|
|||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_superfx(XML::Node &root) {
|
||||
|
|
|
@ -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
|
||||
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) {
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
|
||||
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) {
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
|
||||
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);
|
||||
}
|
||||
|
||||
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(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(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(within<0x70, 0x77, 0x0000, 0xffff>(addr)) {
|
||||
if((addr & 0xf80000) == 0x700000) { //$70-77:0000-ffff
|
||||
return memory_access(write, psram, addr & 0x07ffff, data);
|
||||
}
|
||||
|
||||
if(within<0x00, 0x3f, 0x8000, 0xffff>(addr)
|
||||
|| within<0x40, 0x7f, 0x0000, 0xffff>(addr)
|
||||
|| within<0x80, 0xbf, 0x8000, 0xffff>(addr)
|
||||
|| within<0xc0, 0xff, 0x0000, 0xffff>(addr)
|
||||
if(((addr & 0x408000) == 0x008000) //$00-3f|80-bf:8000-ffff
|
||||
|| ((addr & 0x400000) == 0x400000) //$40-7f|c0-ff:0000-ffff
|
||||
) {
|
||||
if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
||||
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) {
|
||||
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -114,14 +112,14 @@ uint8 BSXCartridge::mmio_read(unsigned addr) {
|
|||
}
|
||||
|
||||
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;
|
||||
r[n] = data;
|
||||
if(n == 0x0e && data & 0x80) mmio_commit();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@ struct Coprocessor : Processor {
|
|||
alwaysinline void synchronize_cpu();
|
||||
};
|
||||
|
||||
#if defined(GAMEBOY)
|
||||
#include <snes/chip/icd2/icd2.hpp>
|
||||
#endif
|
||||
|
||||
#include <snes/chip/nss/nss.hpp>
|
||||
#include <snes/chip/icd2/icd2.hpp>
|
||||
#include <snes/chip/superfx/superfx.hpp>
|
||||
#include <snes/chip/sa1/sa1.hpp>
|
||||
#include <snes/chip/necdsp/necdsp.hpp>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#if defined(GAMEBOY)
|
||||
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define ICD2_CPP
|
||||
|
@ -73,3 +75,5 @@ void ICD2::reset() {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -83,6 +83,8 @@ void CPU::enter() {
|
|||
}
|
||||
|
||||
void CPU::op_step() {
|
||||
debugger.op_exec(regs.pc.d);
|
||||
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
}
|
||||
|
||||
|
|
|
@ -133,6 +133,13 @@ private:
|
|||
|
||||
static void Enter();
|
||||
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;
|
||||
|
|
|
@ -11,6 +11,8 @@ void CPU::op_io() {
|
|||
}
|
||||
|
||||
uint8 CPU::op_read(uint32 addr) {
|
||||
debugger.op_read(addr);
|
||||
|
||||
status.clock_count = speed(addr);
|
||||
dma_edge();
|
||||
add_clocks(status.clock_count - 4);
|
||||
|
@ -21,6 +23,8 @@ uint8 CPU::op_read(uint32 addr) {
|
|||
}
|
||||
|
||||
void CPU::op_write(uint32 addr, uint8 data) {
|
||||
debugger.op_write(addr, data);
|
||||
|
||||
alu_edge();
|
||||
status.clock_count = speed(addr);
|
||||
dma_edge();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef SNES_HPP
|
||||
#define SNES_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
|
@ -17,84 +19,11 @@ namespace SNES {
|
|||
|
||||
#include <libco/libco.h>
|
||||
|
||||
#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/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>
|
||||
#if defined(GAMEBOY)
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#endif
|
||||
|
||||
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 {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
|
|
|
@ -58,7 +58,9 @@ void System::serialize_all(serializer &s) {
|
|||
dsp.serialize(s);
|
||||
|
||||
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s);
|
||||
#if defined(GAMEBOY)
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s);
|
||||
#endif
|
||||
if(cartridge.has_superfx()) superfx.serialize(s);
|
||||
if(cartridge.has_sa1()) sa1.serialize(s);
|
||||
if(cartridge.has_necdsp()) necdsp.serialize(s);
|
||||
|
|
|
@ -65,7 +65,9 @@ void System::runthreadtosave() {
|
|||
void System::init() {
|
||||
assert(interface != 0);
|
||||
|
||||
#if defined(GAMEBOY)
|
||||
icd2.init();
|
||||
#endif
|
||||
nss.init();
|
||||
superfx.init();
|
||||
sa1.init();
|
||||
|
@ -104,7 +106,9 @@ void System::load() {
|
|||
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.load();
|
||||
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.load();
|
||||
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.load();
|
||||
#if defined(GAMEBOY)
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.load();
|
||||
#endif
|
||||
|
||||
if(cartridge.has_bsx_slot()) bsxflash.load();
|
||||
if(cartridge.has_nss_dip()) nss.load();
|
||||
|
@ -128,7 +132,9 @@ void System::unload() {
|
|||
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.unload();
|
||||
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.unload();
|
||||
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.unload();
|
||||
#if defined(GAMEBOY)
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.unload();
|
||||
#endif
|
||||
|
||||
if(cartridge.has_bsx_slot()) bsxflash.unload();
|
||||
if(cartridge.has_nss_dip()) nss.unload();
|
||||
|
@ -164,7 +170,9 @@ void System::power() {
|
|||
|
||||
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.power();
|
||||
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.power();
|
||||
#if defined(GAMEBOY)
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.power();
|
||||
#endif
|
||||
|
||||
if(cartridge.has_bsx_slot()) bsxflash.power();
|
||||
if(cartridge.has_nss_dip()) nss.power();
|
||||
|
@ -192,7 +200,9 @@ void System::reset() {
|
|||
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.reset();
|
||||
|
||||
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.reset();
|
||||
#if defined(GAMEBOY)
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.reset();
|
||||
#endif
|
||||
|
||||
if(cartridge.has_bsx_slot()) bsxflash.reset();
|
||||
if(cartridge.has_nss_dip()) nss.reset();
|
||||
|
@ -208,7 +218,9 @@ void System::reset() {
|
|||
if(cartridge.has_msu1()) msu1.reset();
|
||||
if(cartridge.has_link()) link.reset();
|
||||
|
||||
#if defined(GAMEBOY)
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2);
|
||||
#endif
|
||||
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
|
||||
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
|
||||
if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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))
|
||||
});
|
||||
};
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
struct VideoWindow : Window {
|
||||
VerticalLayout layout;
|
||||
Canvas canvas;
|
||||
|
||||
VideoWindow();
|
||||
};
|
||||
|
||||
extern VideoWindow *videoWindow;
|
|
@ -79,7 +79,8 @@ struct Interface : public SNES::Interface {
|
|||
static Interface interface;
|
||||
|
||||
const char* snes_library_id(void) {
|
||||
return "bsnes v085";
|
||||
static string version = {"bsnes v", Version};
|
||||
return version;
|
||||
}
|
||||
|
||||
unsigned snes_library_revision_major(void) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
include $(nes)/Makefile
|
||||
include $(snes)/Makefile
|
||||
include $(gameboy)/Makefile
|
||||
include $(snes)/Makefile
|
||||
name := bsnes
|
||||
|
||||
ui_objects := ui-main ui-config ui-interface ui-input ui-utility
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <nes/nes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#include <nall/compositor.hpp>
|
||||
#include <nall/config.hpp>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "base.hpp"
|
||||
|
||||
Application *application = 0;
|
||||
Application *application = nullptr;
|
||||
nall::DSP dspaudio;
|
||||
|
||||
//allow files to exist in the same folder as binary;
|
||||
|
@ -27,7 +27,7 @@ void Application::run() {
|
|||
}
|
||||
|
||||
Application::Application(int argc, char **argv) {
|
||||
title = "bsnes v085.03";
|
||||
title = {"bsnes v", Version};
|
||||
|
||||
application = this;
|
||||
quit = false;
|
||||
|
|
Loading…
Reference in New Issue