mirror of https://github.com/bsnes-emu/bsnes.git
Update to v095r04 release.
Changelog: - S-SMP core code style updated - S-SMP loads reset vector from IPLROM ($fffe-ffff) - sfc/base => sfc/expansion - system/input => system/device - added expansion/eBoot (simulation of defparam's SNES-Boot device) - expansion port device can now be selected from Super Famicom menu option - improved GBA MROM/SRAM reading endrift's memory test is up to 1388/1552. Note: I added the expansion port devices to the same group as controller ports. I also had to move "None" to the top of the list. Before v096, I am going to have to add caching of port selections to the configuration file, check the proper default item in the system menu, and remove the items with no mappings from the input configuration window. Lots of work >_>
This commit is contained in:
parent
0fe55e3f5b
commit
d1ffd59c29
|
@ -7,7 +7,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "095.03";
|
static const string Version = "095.04";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
@ -54,75 +54,6 @@ template<typename R, typename... P> struct hook<R (P...)> {
|
||||||
#define privileged private
|
#define privileged private
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef int1_t int1;
|
using varuint = varuint_t<uint>;
|
||||||
typedef int2_t int2;
|
|
||||||
typedef int3_t int3;
|
|
||||||
typedef int4_t int4;
|
|
||||||
typedef int5_t int5;
|
|
||||||
typedef int6_t int6;
|
|
||||||
typedef int7_t int7;
|
|
||||||
typedef int8_t int8;
|
|
||||||
typedef int9_t int9;
|
|
||||||
typedef int10_t int10;
|
|
||||||
typedef int11_t int11;
|
|
||||||
typedef int12_t int12;
|
|
||||||
typedef int13_t int13;
|
|
||||||
typedef int14_t int14;
|
|
||||||
typedef int15_t int15;
|
|
||||||
typedef int16_t int16;
|
|
||||||
typedef int17_t int17;
|
|
||||||
typedef int18_t int18;
|
|
||||||
typedef int19_t int19;
|
|
||||||
typedef int20_t int20;
|
|
||||||
typedef int21_t int21;
|
|
||||||
typedef int22_t int22;
|
|
||||||
typedef int23_t int23;
|
|
||||||
typedef int24_t int24;
|
|
||||||
typedef int25_t int25;
|
|
||||||
typedef int26_t int26;
|
|
||||||
typedef int27_t int27;
|
|
||||||
typedef int28_t int28;
|
|
||||||
typedef int29_t int29;
|
|
||||||
typedef int30_t int30;
|
|
||||||
typedef int31_t int31;
|
|
||||||
typedef int32_t int32;
|
|
||||||
typedef int64_t int64;
|
|
||||||
|
|
||||||
typedef uint1_t uint1;
|
|
||||||
typedef uint2_t uint2;
|
|
||||||
typedef uint3_t uint3;
|
|
||||||
typedef uint4_t uint4;
|
|
||||||
typedef uint5_t uint5;
|
|
||||||
typedef uint6_t uint6;
|
|
||||||
typedef uint7_t uint7;
|
|
||||||
typedef uint8_t uint8;
|
|
||||||
typedef uint9_t uint9;
|
|
||||||
typedef uint10_t uint10;
|
|
||||||
typedef uint11_t uint11;
|
|
||||||
typedef uint12_t uint12;
|
|
||||||
typedef uint13_t uint13;
|
|
||||||
typedef uint14_t uint14;
|
|
||||||
typedef uint15_t uint15;
|
|
||||||
typedef uint16_t uint16;
|
|
||||||
typedef uint17_t uint17;
|
|
||||||
typedef uint18_t uint18;
|
|
||||||
typedef uint19_t uint19;
|
|
||||||
typedef uint20_t uint20;
|
|
||||||
typedef uint21_t uint21;
|
|
||||||
typedef uint22_t uint22;
|
|
||||||
typedef uint23_t uint23;
|
|
||||||
typedef uint24_t uint24;
|
|
||||||
typedef uint25_t uint25;
|
|
||||||
typedef uint26_t uint26;
|
|
||||||
typedef uint27_t uint27;
|
|
||||||
typedef uint28_t uint28;
|
|
||||||
typedef uint29_t uint29;
|
|
||||||
typedef uint30_t uint30;
|
|
||||||
typedef uint31_t uint31;
|
|
||||||
typedef uint32_t uint32;
|
|
||||||
typedef uint_t<33> uint33;
|
|
||||||
typedef uint64_t uint64;
|
|
||||||
|
|
||||||
typedef varuint_t<unsigned> varuint;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,8 +6,8 @@ namespace Emulator {
|
||||||
struct Interface {
|
struct Interface {
|
||||||
struct Information {
|
struct Information {
|
||||||
string name;
|
string name;
|
||||||
unsigned width;
|
uint width;
|
||||||
unsigned height;
|
uint height;
|
||||||
bool overscan;
|
bool overscan;
|
||||||
double aspectRatio;
|
double aspectRatio;
|
||||||
bool resettable;
|
bool resettable;
|
||||||
|
@ -18,7 +18,7 @@ struct Interface {
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
struct Media {
|
struct Media {
|
||||||
unsigned id;
|
uint id;
|
||||||
string name;
|
string name;
|
||||||
string type;
|
string type;
|
||||||
bool bootable; //false for cartridge slots (eg Sufami Turbo cartridges)
|
bool bootable; //false for cartridge slots (eg Sufami Turbo cartridges)
|
||||||
|
@ -26,52 +26,52 @@ struct Interface {
|
||||||
vector<Media> media;
|
vector<Media> media;
|
||||||
|
|
||||||
struct Device {
|
struct Device {
|
||||||
unsigned id;
|
uint id;
|
||||||
unsigned portmask;
|
uint portmask;
|
||||||
string name;
|
string name;
|
||||||
struct Input {
|
struct Input {
|
||||||
unsigned id;
|
uint id;
|
||||||
unsigned type; //0 = digital, 1 = analog (relative), 2 = rumble
|
uint type; //0 = digital, 1 = analog (relative), 2 = rumble
|
||||||
string name;
|
string name;
|
||||||
uintptr_t guid; //user data field
|
uintptr_t guid; //user data field
|
||||||
};
|
};
|
||||||
vector<Input> input;
|
vector<Input> input;
|
||||||
vector<unsigned> order;
|
vector<uint> order;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Port {
|
struct Port {
|
||||||
unsigned id;
|
uint id;
|
||||||
string name;
|
string name;
|
||||||
vector<Device> device;
|
vector<Device> device;
|
||||||
};
|
};
|
||||||
vector<Port> port;
|
vector<Port> port;
|
||||||
|
|
||||||
struct Bind {
|
struct Bind {
|
||||||
virtual auto loadRequest(unsigned, string, string, bool) -> void {}
|
virtual auto loadRequest(uint, string, string, bool) -> void {}
|
||||||
virtual auto loadRequest(unsigned, string, bool) -> void {}
|
virtual auto loadRequest(uint, string, bool) -> void {}
|
||||||
virtual auto saveRequest(unsigned, string) -> void {}
|
virtual auto saveRequest(uint, string) -> void {}
|
||||||
virtual auto videoColor(unsigned, uint16_t, uint16_t, uint16_t, uint16_t) -> uint32_t { return 0u; }
|
virtual auto videoColor(uint, uint16, uint16, uint16, uint16) -> uint32 { return 0u; }
|
||||||
virtual auto videoRefresh(const uint32_t*, const uint32_t*, unsigned, unsigned, unsigned) -> void {}
|
virtual auto videoRefresh(const uint32*, const uint32*, uint, uint, uint) -> void {}
|
||||||
virtual auto audioSample(int16_t, int16_t) -> void {}
|
virtual auto audioSample(int16, int16) -> void {}
|
||||||
virtual auto inputPoll(unsigned, unsigned, unsigned) -> int16_t { return 0; }
|
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
|
||||||
virtual auto inputRumble(unsigned, unsigned, unsigned, bool) -> void {}
|
virtual auto inputRumble(uint, uint, uint, bool) -> void {}
|
||||||
virtual auto dipSettings(const Markup::Node&) -> unsigned { return 0; }
|
virtual auto dipSettings(const Markup::Node&) -> uint { return 0; }
|
||||||
virtual auto path(unsigned) -> string { return ""; }
|
virtual auto path(uint) -> string { return ""; }
|
||||||
virtual auto notify(string text) -> void { print(text, "\n"); }
|
virtual auto notify(string text) -> void { print(text, "\n"); }
|
||||||
};
|
};
|
||||||
Bind* bind = nullptr;
|
Bind* bind = nullptr;
|
||||||
|
|
||||||
//callback bindings (provided by user interface)
|
//callback bindings (provided by user interface)
|
||||||
auto loadRequest(unsigned id, string name, string type, bool required) -> void { return bind->loadRequest(id, name, type, required); }
|
auto loadRequest(uint id, string name, string type, bool required) -> void { return bind->loadRequest(id, name, type, required); }
|
||||||
auto loadRequest(unsigned id, string path, bool required) -> void { return bind->loadRequest(id, path, required); }
|
auto loadRequest(uint id, string path, bool required) -> void { return bind->loadRequest(id, path, required); }
|
||||||
auto saveRequest(unsigned id, string path) -> void { return bind->saveRequest(id, path); }
|
auto saveRequest(uint id, string path) -> void { return bind->saveRequest(id, path); }
|
||||||
auto videoColor(unsigned source, uint16_t alpha, uint16_t red, uint16_t green, uint16_t blue) -> uint32_t { return bind->videoColor(source, alpha, red, green, blue); }
|
auto videoColor(uint source, uint16 alpha, uint16 red, uint16 green, uint16 blue) -> uint32 { return bind->videoColor(source, alpha, red, green, blue); }
|
||||||
auto videoRefresh(const uint32_t* palette, const uint32_t* data, unsigned pitch, unsigned width, unsigned height) -> void { return bind->videoRefresh(palette, data, pitch, width, height); }
|
auto videoRefresh(const uint32* palette, const uint32* data, uint pitch, uint width, uint height) -> void { return bind->videoRefresh(palette, data, pitch, width, height); }
|
||||||
auto audioSample(int16_t lsample, int16_t rsample) -> void { return bind->audioSample(lsample, rsample); }
|
auto audioSample(int16 lsample, int16 rsample) -> void { return bind->audioSample(lsample, rsample); }
|
||||||
auto inputPoll(unsigned port, unsigned device, unsigned input) -> int16_t { return bind->inputPoll(port, device, input); }
|
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
|
||||||
auto inputRumble(unsigned port, unsigned device, unsigned input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
auto inputRumble(uint port, uint device, uint input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
||||||
auto dipSettings(const Markup::Node& node) -> unsigned { return bind->dipSettings(node); }
|
auto dipSettings(const Markup::Node& node) -> uint { return bind->dipSettings(node); }
|
||||||
auto path(unsigned group) -> string { return bind->path(group); }
|
auto path(uint group) -> string { return bind->path(group); }
|
||||||
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
|
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
|
||||||
|
|
||||||
//information
|
//information
|
||||||
|
@ -82,15 +82,15 @@ struct Interface {
|
||||||
//media interface
|
//media interface
|
||||||
virtual auto loaded() -> bool { return false; }
|
virtual auto loaded() -> bool { return false; }
|
||||||
virtual auto sha256() -> string { return ""; }
|
virtual auto sha256() -> string { return ""; }
|
||||||
virtual auto group(unsigned id) -> unsigned = 0;
|
virtual auto group(uint id) -> uint = 0;
|
||||||
virtual auto load(unsigned id) -> void {}
|
virtual auto load(uint id) -> void {}
|
||||||
virtual auto save() -> void {}
|
virtual auto save() -> void {}
|
||||||
virtual auto load(unsigned id, const stream& memory) -> void {}
|
virtual auto load(uint id, const stream& memory) -> void {}
|
||||||
virtual auto save(unsigned id, const stream& memory) -> void {}
|
virtual auto save(uint id, const stream& memory) -> void {}
|
||||||
virtual auto unload() -> void {}
|
virtual auto unload() -> void {}
|
||||||
|
|
||||||
//system interface
|
//system interface
|
||||||
virtual auto connect(unsigned port, unsigned device) -> void {}
|
virtual auto connect(uint port, uint device) -> void {}
|
||||||
virtual auto power() -> void {}
|
virtual auto power() -> void {}
|
||||||
virtual auto reset() -> void {}
|
virtual auto reset() -> void {}
|
||||||
virtual auto run() -> void {}
|
virtual auto run() -> void {}
|
||||||
|
@ -107,7 +107,7 @@ struct Interface {
|
||||||
virtual auto cheatSet(const lstring& = lstring{}) -> void {}
|
virtual auto cheatSet(const lstring& = lstring{}) -> void {}
|
||||||
|
|
||||||
//utility functions
|
//utility functions
|
||||||
enum class PaletteMode : unsigned { Literal, Channel, Standard, Emulation };
|
enum class PaletteMode : uint { Literal, Channel, Standard, Emulation };
|
||||||
virtual auto paletteUpdate(PaletteMode mode) -> void {}
|
virtual auto paletteUpdate(PaletteMode mode) -> void {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
namespace Famicom {
|
namespace Famicom {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const string Name = "bnes";
|
static const string Name = "bnes";
|
||||||
static const unsigned SerializerVersion = 2;
|
static const uint SerializerVersion = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ namespace Famicom {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto create(void (*entrypoint)(), unsigned frequency) -> void {
|
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||||
this->frequency = frequency;
|
this->frequency = frequency;
|
||||||
|
@ -39,7 +39,7 @@ namespace Famicom {
|
||||||
}
|
}
|
||||||
|
|
||||||
cothread_t thread = nullptr;
|
cothread_t thread = nullptr;
|
||||||
unsigned frequency = 0;
|
uint frequency = 0;
|
||||||
int64 clock = 0;
|
int64 clock = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const string Name = "bgb";
|
static const string Name = "bgb";
|
||||||
static const unsigned SerializerVersion = 4;
|
static const uint SerializerVersion = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ namespace GameBoy {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto create(void (*entrypoint)(), unsigned frequency) -> void {
|
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||||
this->frequency = frequency;
|
this->frequency = frequency;
|
||||||
|
@ -39,8 +39,8 @@ namespace GameBoy {
|
||||||
}
|
}
|
||||||
|
|
||||||
cothread_t thread = nullptr;
|
cothread_t thread = nullptr;
|
||||||
unsigned frequency = 0;
|
uint frequency = 0;
|
||||||
int64_t clock = 0;
|
int64 clock = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <gb/memory/memory.hpp>
|
#include <gb/memory/memory.hpp>
|
||||||
|
|
|
@ -10,7 +10,6 @@ namespace GameBoyAdvance {
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
Cartridge::Cartridge() {
|
Cartridge::Cartridge() {
|
||||||
loaded = false;
|
|
||||||
mrom.data = new uint8[mrom.size = 32 * 1024 * 1024];
|
mrom.data = new uint8[mrom.size = 32 * 1024 * 1024];
|
||||||
sram.data = new uint8[sram.size = 32 * 1024];
|
sram.data = new uint8[sram.size = 32 * 1024];
|
||||||
eeprom.data = new uint8[eeprom.size = 8 * 1024];
|
eeprom.data = new uint8[eeprom.size = 8 * 1024];
|
||||||
|
@ -24,6 +23,14 @@ Cartridge::~Cartridge() {
|
||||||
delete[] flash.data;
|
delete[] flash.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Cartridge::loaded() const -> bool {
|
||||||
|
return isLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::sha256() const -> string {
|
||||||
|
return information.sha256;
|
||||||
|
}
|
||||||
|
|
||||||
auto Cartridge::title() const -> string {
|
auto Cartridge::title() const -> string {
|
||||||
return information.title;
|
return information.title;
|
||||||
}
|
}
|
||||||
|
@ -34,21 +41,18 @@ auto Cartridge::load() -> void {
|
||||||
auto document = BML::unserialize(information.markup);
|
auto document = BML::unserialize(information.markup);
|
||||||
information.title = document["information/title"].text();
|
information.title = document["information/title"].text();
|
||||||
|
|
||||||
unsigned mrom_size = 0;
|
hasSRAM = false;
|
||||||
|
hasEEPROM = false;
|
||||||
|
hasFLASH = false;
|
||||||
|
|
||||||
if(auto info = document["cartridge/mrom"]) {
|
if(auto info = document["cartridge/mrom"]) {
|
||||||
|
mrom.size = min(32 * 1024 * 1024, info["size"].decimal());
|
||||||
|
|
||||||
interface->loadRequest(ID::MROM, info["name"].text(), true);
|
interface->loadRequest(ID::MROM, info["name"].text(), true);
|
||||||
mrom_size = info["size"].decimal();
|
|
||||||
for(unsigned addr = mrom_size; addr < mrom.size; addr++) {
|
|
||||||
mrom.data[addr] = mrom.data[Bus::mirror(addr, mrom_size)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
has_sram = false;
|
|
||||||
has_eeprom = false;
|
|
||||||
has_flash = false;
|
|
||||||
|
|
||||||
if(auto info = document["cartridge/sram"]) {
|
if(auto info = document["cartridge/sram"]) {
|
||||||
has_sram = true;
|
hasSRAM = true;
|
||||||
sram.size = min(32 * 1024, info["size"].decimal());
|
sram.size = min(32 * 1024, info["size"].decimal());
|
||||||
sram.mask = sram.size - 1;
|
sram.mask = sram.size - 1;
|
||||||
for(auto n : range(sram.size)) sram.data[n] = 0xff;
|
for(auto n : range(sram.size)) sram.data[n] = 0xff;
|
||||||
|
@ -58,12 +62,12 @@ auto Cartridge::load() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto info = document["cartridge/eeprom"]) {
|
if(auto info = document["cartridge/eeprom"]) {
|
||||||
has_eeprom = true;
|
hasEEPROM = true;
|
||||||
eeprom.size = min(8 * 1024, info["size"].decimal());
|
eeprom.size = min(8 * 1024, info["size"].decimal());
|
||||||
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
||||||
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
||||||
eeprom.mask = mrom_size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||||
eeprom.test = mrom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||||
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
|
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
|
||||||
|
|
||||||
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
|
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
|
||||||
|
@ -71,7 +75,7 @@ auto Cartridge::load() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto info = document["cartridge/flash"]) {
|
if(auto info = document["cartridge/flash"]) {
|
||||||
has_flash = true;
|
hasFLASH = true;
|
||||||
flash.id = info["id"].decimal();
|
flash.id = info["id"].decimal();
|
||||||
flash.size = min(128 * 1024, info["size"].decimal());
|
flash.size = min(128 * 1024, info["size"].decimal());
|
||||||
for(auto n : range(flash.size)) flash.data[n] = 0xff;
|
for(auto n : range(flash.size)) flash.data[n] = 0xff;
|
||||||
|
@ -85,15 +89,15 @@ auto Cartridge::load() -> void {
|
||||||
memory.append({ID::FLASH, info["name"].text()});
|
memory.append({ID::FLASH, info["name"].text()});
|
||||||
}
|
}
|
||||||
|
|
||||||
sha256 = Hash::SHA256(mrom.data, mrom_size).digest();
|
information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest();
|
||||||
|
|
||||||
system.load();
|
system.load();
|
||||||
loaded = true;
|
isLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::unload() -> void {
|
auto Cartridge::unload() -> void {
|
||||||
if(loaded) {
|
if(isLoaded) {
|
||||||
loaded = false;
|
isLoaded = false;
|
||||||
memory.reset();
|
memory.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,24 +109,24 @@ auto Cartridge::power() -> void {
|
||||||
|
|
||||||
#define RAM_ANALYZE
|
#define RAM_ANALYZE
|
||||||
|
|
||||||
auto Cartridge::read(unsigned mode, uint32 addr) -> uint32 {
|
auto Cartridge::read(uint mode, uint32 addr) -> uint32 {
|
||||||
if(addr < 0x0e00'0000) {
|
if(addr < 0x0e00'0000) {
|
||||||
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.read();
|
if(hasEEPROM && (addr & eeprom.mask) == eeprom.test) return eeprom.read();
|
||||||
return mrom.read(mode, addr);
|
return mrom.read(mode, addr);
|
||||||
} else {
|
} else {
|
||||||
if(has_sram) return sram.read(mode, addr);
|
if(hasSRAM) return sram.read(mode, addr);
|
||||||
if(has_flash) return flash.read(addr);
|
if(hasFLASH) return flash.read(addr);
|
||||||
return cpu.pipeline.fetch.instruction;
|
return cpu.pipeline.fetch.instruction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
auto Cartridge::write(uint mode, uint32 addr, uint32 word) -> void {
|
||||||
if(addr < 0x0e00'0000) {
|
if(addr < 0x0e00'0000) {
|
||||||
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
|
if(hasEEPROM && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
|
||||||
return mrom.write(mode, addr, word);
|
return mrom.write(mode, addr, word);
|
||||||
} else {
|
} else {
|
||||||
if(has_sram) return sram.write(mode, addr, word);
|
if(hasSRAM) return sram.write(mode, addr, word);
|
||||||
if(has_flash) return flash.write(addr, word);
|
if(hasFLASH) return flash.write(addr, word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
struct Cartridge : property<Cartridge> {
|
struct Cartridge {
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
readonly<bool> loaded;
|
auto loaded() const -> bool;
|
||||||
readonly<string> sha256;
|
auto sha256() const -> string;
|
||||||
|
auto title() const -> string;
|
||||||
readonly<bool> has_sram;
|
|
||||||
readonly<bool> has_eeprom;
|
|
||||||
readonly<bool> has_flash;
|
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string markup;
|
string markup;
|
||||||
|
string sha256;
|
||||||
string title;
|
string title;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
struct Media {
|
struct Media {
|
||||||
unsigned id;
|
uint id;
|
||||||
string name;
|
string name;
|
||||||
};
|
};
|
||||||
vector<Media> memory;
|
vector<Media> memory;
|
||||||
|
@ -22,16 +20,20 @@ struct Cartridge : property<Cartridge> {
|
||||||
Cartridge();
|
Cartridge();
|
||||||
~Cartridge();
|
~Cartridge();
|
||||||
|
|
||||||
auto title() const -> string;
|
|
||||||
|
|
||||||
auto load() -> void;
|
auto load() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
auto read(unsigned mode, uint32 addr) -> uint32;
|
auto read(uint mode, uint32 addr) -> uint32;
|
||||||
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
auto write(uint mode, uint32 addr, uint32 word) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isLoaded = false;
|
||||||
|
bool hasSRAM = false;
|
||||||
|
bool hasEEPROM = false;
|
||||||
|
bool hasFLASH = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Cartridge cartridge;
|
extern Cartridge cartridge;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
auto Cartridge::EEPROM::read(unsigned addr) -> bool {
|
auto Cartridge::EEPROM::read(uint addr) -> bool {
|
||||||
return data[addr >> 3] & 0x80 >> (addr & 7);
|
return data[addr >> 3] & 0x80 >> (addr & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::EEPROM::write(unsigned addr, bool bit) -> void {
|
auto Cartridge::EEPROM::write(uint addr, bool bit) -> void {
|
||||||
if(bit == 0) data[addr >> 3] &=~ (0x80 >> (addr & 7));
|
if(bit == 0) data[addr >> 3] &=~ (0x80 >> (addr & 7));
|
||||||
if(bit == 1) data[addr >> 3] |= (0x80 >> (addr & 7));
|
if(bit == 1) data[addr >> 3] |= (0x80 >> (addr & 7));
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ auto Cartridge::EEPROM::serialize(serializer& s) -> void {
|
||||||
s.integer(mask);
|
s.integer(mask);
|
||||||
s.integer(test);
|
s.integer(test);
|
||||||
s.integer(bits);
|
s.integer(bits);
|
||||||
s.integer((unsigned&)mode);
|
s.integer((uint&)mode);
|
||||||
s.integer(offset);
|
s.integer(offset);
|
||||||
s.integer(address);
|
s.integer(address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,41 @@
|
||||||
struct Memory {
|
struct MROM {
|
||||||
auto ror(uint32 word, unsigned shift) -> uint32 {
|
|
||||||
return word << 32 - shift | word >> shift;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MROM : Memory {
|
|
||||||
uint8* data;
|
uint8* data;
|
||||||
unsigned size;
|
uint size;
|
||||||
unsigned mask;
|
uint mask;
|
||||||
|
|
||||||
auto read(unsigned mode, uint32 addr) -> uint32;
|
auto read(uint mode, uint32 addr) -> uint32;
|
||||||
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
auto write(uint mode, uint32 addr, uint32 word) -> void;
|
||||||
|
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
} mrom;
|
} mrom;
|
||||||
|
|
||||||
struct SRAM : Memory {
|
struct SRAM {
|
||||||
uint8* data;
|
uint8* data;
|
||||||
unsigned size;
|
uint size;
|
||||||
unsigned mask;
|
uint mask;
|
||||||
|
|
||||||
auto read(unsigned mode, uint32 addr) -> uint32;
|
auto read(uint mode, uint32 addr) -> uint32;
|
||||||
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
auto write(uint mode, uint32 addr, uint32 word) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
} sram;
|
} sram;
|
||||||
|
|
||||||
struct EEPROM : Memory {
|
struct EEPROM {
|
||||||
uint8* data;
|
uint8* data;
|
||||||
unsigned size;
|
uint size;
|
||||||
unsigned mask;
|
uint mask;
|
||||||
unsigned test;
|
uint test;
|
||||||
unsigned bits;
|
uint bits;
|
||||||
|
|
||||||
enum class Mode : unsigned {
|
enum class Mode : uint {
|
||||||
Wait, Command, ReadAddress, ReadValidate, ReadData, WriteAddress, WriteData, WriteValidate
|
Wait, Command, ReadAddress, ReadValidate, ReadData, WriteAddress, WriteData, WriteValidate
|
||||||
} mode;
|
} mode;
|
||||||
unsigned offset;
|
uint offset;
|
||||||
unsigned address;
|
uint address;
|
||||||
unsigned addressbits;
|
uint addressbits;
|
||||||
|
|
||||||
auto read(unsigned addr) -> bool;
|
auto read(uint addr) -> bool;
|
||||||
auto write(unsigned addr, bool bit) -> void;
|
auto write(uint addr, bool bit) -> void;
|
||||||
|
|
||||||
auto read() -> bool;
|
auto read() -> bool;
|
||||||
auto write(bool bit) -> void;
|
auto write(bool bit) -> void;
|
||||||
|
@ -47,9 +43,9 @@ struct EEPROM : Memory {
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
} eeprom;
|
} eeprom;
|
||||||
|
|
||||||
struct FLASH : Memory {
|
struct FLASH {
|
||||||
uint8* data;
|
uint8* data;
|
||||||
unsigned size;
|
uint size;
|
||||||
uint16 id;
|
uint16 id;
|
||||||
|
|
||||||
bool unlockhi;
|
bool unlockhi;
|
||||||
|
|
|
@ -1,12 +1,23 @@
|
||||||
auto Cartridge::MROM::read(unsigned mode, uint32 addr) -> uint32 {
|
auto Cartridge::MROM::read(uint mode, uint32 addr) -> uint32 {
|
||||||
if(mode & Word) addr &= ~3;
|
if(mode & Word) {
|
||||||
|
uint32 word = 0;
|
||||||
|
word |= read(mode & ~Word | Half, (addr & ~3) + 0) << 0;
|
||||||
|
word |= read(mode & ~Word | Half, (addr & ~3) + 2) << 16;
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr &= 0x01ff'ffff;
|
||||||
|
if(addr >= size) return (uint16)(addr >> 1);
|
||||||
|
|
||||||
if(mode & Half) addr &= ~1;
|
if(mode & Half) addr &= ~1;
|
||||||
auto p = data + (addr & 0x01ff'ffff);
|
auto p = data + addr;
|
||||||
if(mode & Word) return p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24;
|
|
||||||
if(mode & Half) return p[0] << 0 | p[1] << 8;
|
if(mode & Half) return p[0] << 0 | p[1] << 8;
|
||||||
if(mode & Byte) return p[0] << 0;
|
if(mode & Byte) return p[0] << 0;
|
||||||
return 0; //should never occur
|
return 0; //should never occur
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::MROM::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
auto Cartridge::MROM::write(uint mode, uint32 addr, uint32 word) -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::MROM::serialize(serializer& s) -> void {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
void Cartridge::serialize(serializer& s) {
|
void Cartridge::serialize(serializer& s) {
|
||||||
if(has_sram) sram.serialize(s);
|
mrom.serialize(s);
|
||||||
if(has_eeprom) eeprom.serialize(s);
|
if(hasSRAM) sram.serialize(s);
|
||||||
if(has_flash) flash.serialize(s);
|
if(hasEEPROM) eeprom.serialize(s);
|
||||||
|
if(hasFLASH) flash.serialize(s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
auto Cartridge::SRAM::read(unsigned mode, uint32 addr) -> uint32 {
|
auto Cartridge::SRAM::read(uint mode, uint32 addr) -> uint32 {
|
||||||
if(mode & Word) addr &= ~3;
|
|
||||||
if(mode & Half) addr &= ~1;
|
|
||||||
uint32 word = data[addr & mask];
|
uint32 word = data[addr & mask];
|
||||||
word = ror(word, 8 * (addr & 3));
|
word |= word << 8;
|
||||||
if(mode & Word) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
word |= word << 16;
|
||||||
if(mode & Half) { word &= 0xff; word |= word << 8; }
|
|
||||||
return word;
|
return word;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::SRAM::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
auto Cartridge::SRAM::write(uint mode, uint32 addr, uint32 word) -> void {
|
||||||
data[addr & mask] = ror(word, 8 * (addr & 3));
|
data[addr & mask] = word;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::SRAM::serialize(serializer& s) -> void {
|
auto Cartridge::SRAM::serialize(serializer& s) -> void {
|
||||||
|
|
11
gba/gba.hpp
11
gba/gba.hpp
|
@ -7,7 +7,7 @@
|
||||||
namespace GameBoyAdvance {
|
namespace GameBoyAdvance {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const string Name = "bgba";
|
static const string Name = "bgba";
|
||||||
static const unsigned SerializerVersion = 2;
|
static const uint SerializerVersion = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ namespace GameBoyAdvance {
|
||||||
#include <libco/libco.h>
|
#include <libco/libco.h>
|
||||||
|
|
||||||
namespace GameBoyAdvance {
|
namespace GameBoyAdvance {
|
||||||
enum : unsigned { //mode flags for bus_read, bus_write:
|
enum : uint { //mode flags for bus read, write:
|
||||||
Nonsequential = 1, //N cycle
|
Nonsequential = 1, //N cycle
|
||||||
Sequential = 2, //S cycle
|
Sequential = 2, //S cycle
|
||||||
Prefetch = 4, //instruction fetch (eligible for prefetch)
|
Prefetch = 4, //instruction fetch (eligible for prefetch)
|
||||||
|
@ -30,6 +30,7 @@ namespace GameBoyAdvance {
|
||||||
Word = 32, //32-bit access
|
Word = 32, //32-bit access
|
||||||
Load = 64, //load operation
|
Load = 64, //load operation
|
||||||
Store = 128, //store operation
|
Store = 128, //store operation
|
||||||
|
Signed = 256, //sign extended
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Thread {
|
struct Thread {
|
||||||
|
@ -37,7 +38,7 @@ namespace GameBoyAdvance {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto create(void (*entrypoint)(), unsigned frequency) -> void {
|
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||||
this->frequency = frequency;
|
this->frequency = frequency;
|
||||||
|
@ -50,8 +51,8 @@ namespace GameBoyAdvance {
|
||||||
}
|
}
|
||||||
|
|
||||||
cothread_t thread = nullptr;
|
cothread_t thread = nullptr;
|
||||||
unsigned frequency = 0;
|
uint frequency = 0;
|
||||||
signed clock = 0;
|
int clock = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <gba/memory/memory.hpp>
|
#include <gba/memory/memory.hpp>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef NALL_STDINT_HPP
|
#ifndef NALL_STDINT_HPP
|
||||||
#define NALL_STDINT_HPP
|
#define NALL_STDINT_HPP
|
||||||
|
|
||||||
|
using uint = unsigned int;
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
typedef signed char int8_t;
|
typedef signed char int8_t;
|
||||||
typedef signed short int16_t;
|
typedef signed short int16_t;
|
||||||
|
|
200
nall/varint.hpp
200
nall/varint.hpp
|
@ -145,75 +145,139 @@ private:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//typedefs
|
using int1 = nall::int_t<1>;
|
||||||
typedef nall::uint_t< 1> uint1_t;
|
using int2 = nall::int_t<2>;
|
||||||
typedef nall::uint_t< 2> uint2_t;
|
using int3 = nall::int_t<3>;
|
||||||
typedef nall::uint_t< 3> uint3_t;
|
using int4 = nall::int_t<4>;
|
||||||
typedef nall::uint_t< 4> uint4_t;
|
using int5 = nall::int_t<5>;
|
||||||
typedef nall::uint_t< 5> uint5_t;
|
using int6 = nall::int_t<6>;
|
||||||
typedef nall::uint_t< 6> uint6_t;
|
using int7 = nall::int_t<7>;
|
||||||
typedef nall::uint_t< 7> uint7_t;
|
using int8 = int8_t;
|
||||||
//typedef nall::uint_t< 8> uint8_t;
|
using int9 = nall::int_t<9>;
|
||||||
|
using int10 = nall::int_t<10>;
|
||||||
|
using int11 = nall::int_t<11>;
|
||||||
|
using int12 = nall::int_t<12>;
|
||||||
|
using int13 = nall::int_t<13>;
|
||||||
|
using int14 = nall::int_t<14>;
|
||||||
|
using int15 = nall::int_t<15>;
|
||||||
|
using int16 = int16_t;
|
||||||
|
using int17 = nall::int_t<17>;
|
||||||
|
using int18 = nall::int_t<18>;
|
||||||
|
using int19 = nall::int_t<19>;
|
||||||
|
using int20 = nall::int_t<20>;
|
||||||
|
using int21 = nall::int_t<21>;
|
||||||
|
using int22 = nall::int_t<22>;
|
||||||
|
using int23 = nall::int_t<23>;
|
||||||
|
using int24 = nall::int_t<24>;
|
||||||
|
using int25 = nall::int_t<25>;
|
||||||
|
using int26 = nall::int_t<26>;
|
||||||
|
using int27 = nall::int_t<27>;
|
||||||
|
using int28 = nall::int_t<28>;
|
||||||
|
using int29 = nall::int_t<29>;
|
||||||
|
using int30 = nall::int_t<30>;
|
||||||
|
using int31 = nall::int_t<31>;
|
||||||
|
using int32 = int32_t;
|
||||||
|
using int33 = nall::int_t<33>;
|
||||||
|
using int34 = nall::int_t<34>;
|
||||||
|
using int35 = nall::int_t<35>;
|
||||||
|
using int36 = nall::int_t<36>;
|
||||||
|
using int37 = nall::int_t<37>;
|
||||||
|
using int38 = nall::int_t<38>;
|
||||||
|
using int39 = nall::int_t<39>;
|
||||||
|
using int40 = nall::int_t<40>;
|
||||||
|
using int41 = nall::int_t<41>;
|
||||||
|
using int42 = nall::int_t<42>;
|
||||||
|
using int43 = nall::int_t<43>;
|
||||||
|
using int44 = nall::int_t<44>;
|
||||||
|
using int45 = nall::int_t<45>;
|
||||||
|
using int46 = nall::int_t<46>;
|
||||||
|
using int47 = nall::int_t<47>;
|
||||||
|
using int48 = nall::int_t<48>;
|
||||||
|
using int49 = nall::int_t<49>;
|
||||||
|
using int50 = nall::int_t<50>;
|
||||||
|
using int51 = nall::int_t<51>;
|
||||||
|
using int52 = nall::int_t<52>;
|
||||||
|
using int53 = nall::int_t<53>;
|
||||||
|
using int54 = nall::int_t<54>;
|
||||||
|
using int55 = nall::int_t<55>;
|
||||||
|
using int56 = nall::int_t<56>;
|
||||||
|
using int57 = nall::int_t<57>;
|
||||||
|
using int58 = nall::int_t<58>;
|
||||||
|
using int59 = nall::int_t<59>;
|
||||||
|
using int60 = nall::int_t<60>;
|
||||||
|
using int61 = nall::int_t<61>;
|
||||||
|
using int62 = nall::int_t<62>;
|
||||||
|
using int63 = nall::int_t<63>;
|
||||||
|
using int64 = int64_t;
|
||||||
|
|
||||||
typedef nall::uint_t< 9> uint9_t;
|
using uint1 = nall::uint_t<1>;
|
||||||
typedef nall::uint_t<10> uint10_t;
|
using uint2 = nall::uint_t<2>;
|
||||||
typedef nall::uint_t<11> uint11_t;
|
using uint3 = nall::uint_t<3>;
|
||||||
typedef nall::uint_t<12> uint12_t;
|
using uint4 = nall::uint_t<4>;
|
||||||
typedef nall::uint_t<13> uint13_t;
|
using uint5 = nall::uint_t<5>;
|
||||||
typedef nall::uint_t<14> uint14_t;
|
using uint6 = nall::uint_t<6>;
|
||||||
typedef nall::uint_t<15> uint15_t;
|
using uint7 = nall::uint_t<7>;
|
||||||
//typedef nall::uint_t<16> uint16_t;
|
using uint8 = uint8_t;
|
||||||
|
using uint9 = nall::uint_t<9>;
|
||||||
|
using uint10 = nall::uint_t<10>;
|
||||||
|
using uint11 = nall::uint_t<11>;
|
||||||
|
using uint12 = nall::uint_t<12>;
|
||||||
|
using uint13 = nall::uint_t<13>;
|
||||||
|
using uint14 = nall::uint_t<14>;
|
||||||
|
using uint15 = nall::uint_t<15>;
|
||||||
|
using uint16 = uint16_t;
|
||||||
|
using uint17 = nall::uint_t<17>;
|
||||||
|
using uint18 = nall::uint_t<18>;
|
||||||
|
using uint19 = nall::uint_t<19>;
|
||||||
|
using uint20 = nall::uint_t<20>;
|
||||||
|
using uint21 = nall::uint_t<21>;
|
||||||
|
using uint22 = nall::uint_t<22>;
|
||||||
|
using uint23 = nall::uint_t<23>;
|
||||||
|
using uint24 = nall::uint_t<24>;
|
||||||
|
using uint25 = nall::uint_t<25>;
|
||||||
|
using uint26 = nall::uint_t<26>;
|
||||||
|
using uint27 = nall::uint_t<27>;
|
||||||
|
using uint28 = nall::uint_t<28>;
|
||||||
|
using uint29 = nall::uint_t<29>;
|
||||||
|
using uint30 = nall::uint_t<30>;
|
||||||
|
using uint31 = nall::uint_t<31>;
|
||||||
|
using uint32 = uint32_t;
|
||||||
|
using uint33 = nall::uint_t<33>;
|
||||||
|
using uint34 = nall::uint_t<34>;
|
||||||
|
using uint35 = nall::uint_t<35>;
|
||||||
|
using uint36 = nall::uint_t<36>;
|
||||||
|
using uint37 = nall::uint_t<37>;
|
||||||
|
using uint38 = nall::uint_t<38>;
|
||||||
|
using uint39 = nall::uint_t<39>;
|
||||||
|
using uint40 = nall::uint_t<40>;
|
||||||
|
using uint41 = nall::uint_t<41>;
|
||||||
|
using uint42 = nall::uint_t<42>;
|
||||||
|
using uint43 = nall::uint_t<43>;
|
||||||
|
using uint44 = nall::uint_t<44>;
|
||||||
|
using uint45 = nall::uint_t<45>;
|
||||||
|
using uint46 = nall::uint_t<46>;
|
||||||
|
using uint47 = nall::uint_t<47>;
|
||||||
|
using uint48 = nall::uint_t<48>;
|
||||||
|
using uint49 = nall::uint_t<49>;
|
||||||
|
using uint50 = nall::uint_t<50>;
|
||||||
|
using uint51 = nall::uint_t<51>;
|
||||||
|
using uint52 = nall::uint_t<52>;
|
||||||
|
using uint53 = nall::uint_t<53>;
|
||||||
|
using uint54 = nall::uint_t<54>;
|
||||||
|
using uint55 = nall::uint_t<55>;
|
||||||
|
using uint56 = nall::uint_t<56>;
|
||||||
|
using uint57 = nall::uint_t<57>;
|
||||||
|
using uint58 = nall::uint_t<58>;
|
||||||
|
using uint59 = nall::uint_t<59>;
|
||||||
|
using uint60 = nall::uint_t<60>;
|
||||||
|
using uint61 = nall::uint_t<61>;
|
||||||
|
using uint62 = nall::uint_t<62>;
|
||||||
|
using uint63 = nall::uint_t<63>;
|
||||||
|
using uint64 = uint64_t;
|
||||||
|
|
||||||
typedef nall::uint_t<17> uint17_t;
|
#if defined(__SIZEOF_INT128__)
|
||||||
typedef nall::uint_t<18> uint18_t;
|
using int128 = int128_t;
|
||||||
typedef nall::uint_t<19> uint19_t;
|
using uint128 = uint128_t;
|
||||||
typedef nall::uint_t<20> uint20_t;
|
#endif
|
||||||
typedef nall::uint_t<21> uint21_t;
|
|
||||||
typedef nall::uint_t<22> uint22_t;
|
|
||||||
typedef nall::uint_t<23> uint23_t;
|
|
||||||
typedef nall::uint_t<24> uint24_t;
|
|
||||||
typedef nall::uint_t<25> uint25_t;
|
|
||||||
typedef nall::uint_t<26> uint26_t;
|
|
||||||
typedef nall::uint_t<27> uint27_t;
|
|
||||||
typedef nall::uint_t<28> uint28_t;
|
|
||||||
typedef nall::uint_t<29> uint29_t;
|
|
||||||
typedef nall::uint_t<30> uint30_t;
|
|
||||||
typedef nall::uint_t<31> uint31_t;
|
|
||||||
//typedef nall::uint_t<32> uint32_t;
|
|
||||||
|
|
||||||
typedef nall::int_t< 1> int1_t;
|
|
||||||
typedef nall::int_t< 2> int2_t;
|
|
||||||
typedef nall::int_t< 3> int3_t;
|
|
||||||
typedef nall::int_t< 4> int4_t;
|
|
||||||
typedef nall::int_t< 5> int5_t;
|
|
||||||
typedef nall::int_t< 6> int6_t;
|
|
||||||
typedef nall::int_t< 7> int7_t;
|
|
||||||
//typedef nall::int_t< 8> int8_t;
|
|
||||||
|
|
||||||
typedef nall::int_t< 9> int9_t;
|
|
||||||
typedef nall::int_t<10> int10_t;
|
|
||||||
typedef nall::int_t<11> int11_t;
|
|
||||||
typedef nall::int_t<12> int12_t;
|
|
||||||
typedef nall::int_t<13> int13_t;
|
|
||||||
typedef nall::int_t<14> int14_t;
|
|
||||||
typedef nall::int_t<15> int15_t;
|
|
||||||
//typedef nall::int_t<16> int16_t;
|
|
||||||
|
|
||||||
typedef nall::int_t<17> int17_t;
|
|
||||||
typedef nall::int_t<18> int18_t;
|
|
||||||
typedef nall::int_t<19> int19_t;
|
|
||||||
typedef nall::int_t<20> int20_t;
|
|
||||||
typedef nall::int_t<21> int21_t;
|
|
||||||
typedef nall::int_t<22> int22_t;
|
|
||||||
typedef nall::int_t<23> int23_t;
|
|
||||||
typedef nall::int_t<24> int24_t;
|
|
||||||
typedef nall::int_t<25> int25_t;
|
|
||||||
typedef nall::int_t<26> int26_t;
|
|
||||||
typedef nall::int_t<27> int27_t;
|
|
||||||
typedef nall::int_t<28> int28_t;
|
|
||||||
typedef nall::int_t<29> int29_t;
|
|
||||||
typedef nall::int_t<30> int30_t;
|
|
||||||
typedef nall::int_t<31> int31_t;
|
|
||||||
//typedef nall::int_t<32> int32_t;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
sfc_objects := sfc-interface sfc-system sfc-controller
|
sfc_objects := sfc-interface sfc-system sfc-controller
|
||||||
sfc_objects += sfc-cartridge sfc-cheat
|
sfc_objects += sfc-cartridge sfc-cheat
|
||||||
sfc_objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu
|
sfc_objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu
|
||||||
sfc_objects += sfc-satellaviewbase
|
sfc_objects += sfc-eboot sfc-satellaviewbase
|
||||||
sfc_objects += sfc-icd2 sfc-mcc sfc-nss sfc-event
|
sfc_objects += sfc-icd2 sfc-mcc sfc-nss sfc-event
|
||||||
sfc_objects += sfc-sa1 sfc-superfx
|
sfc_objects += sfc-sa1 sfc-superfx
|
||||||
sfc_objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
|
sfc_objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
|
||||||
|
@ -44,7 +44,8 @@ obj/sfc-smp.o: $(sfcsmp)/smp.cpp $(call rwildcard,$(sfcsmp)/)
|
||||||
obj/sfc-dsp.o: $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/)
|
obj/sfc-dsp.o: $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/)
|
||||||
obj/sfc-ppu.o: $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/)
|
obj/sfc-ppu.o: $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/)
|
||||||
|
|
||||||
obj/sfc-satellaviewbase.o: $(sfc)/base/satellaview/satellaview.cpp $(call rwildcard,$(sfc)/base/satellaview/)
|
obj/sfc-eboot.o: $(sfc)/expansion/eboot/eboot.cpp $(call rwildcard,$(sfc)/expansion/eboot/)
|
||||||
|
obj/sfc-satellaviewbase.o: $(sfc)/expansion/satellaview/satellaview.cpp $(call rwildcard,$(sfc)/expansion/satellaview/)
|
||||||
|
|
||||||
obj/sfc-icd2.o: $(sfc)/chip/icd2/icd2.cpp $(call rwildcard,$(sfc)/chip/icd2/)
|
obj/sfc-icd2.o: $(sfc)/chip/icd2/icd2.cpp $(call rwildcard,$(sfc)/chip/icd2/)
|
||||||
obj/sfc-mcc.o: $(sfc)/chip/mcc/mcc.cpp $(call rwildcard,$(sfc)/chip/mcc/)
|
obj/sfc-mcc.o: $(sfc)/chip/mcc/mcc.cpp $(call rwildcard,$(sfc)/chip/mcc/)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#include <sfc/base/satellaview/satellaview.hpp>
|
|
|
@ -134,7 +134,7 @@ void SA1::power() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SA1::reset() {
|
void SA1::reset() {
|
||||||
create(SA1::Enter, system.cpu_frequency());
|
create(SA1::Enter, system.cpuFrequency());
|
||||||
|
|
||||||
cpubwram.dma = false;
|
cpubwram.dma = false;
|
||||||
for(unsigned addr = 0; addr < iram.size(); addr++) {
|
for(unsigned addr = 0; addr < iram.size(); addr++) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ auto SuperFX::power() -> void {
|
||||||
|
|
||||||
auto SuperFX::reset() -> void {
|
auto SuperFX::reset() -> void {
|
||||||
GSU::reset();
|
GSU::reset();
|
||||||
create(SuperFX::Enter, system.cpu_frequency());
|
create(SuperFX::Enter, system.cpuFrequency());
|
||||||
memory_reset();
|
memory_reset();
|
||||||
timing_reset();
|
timing_reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@ Controller::Controller(bool port) : port(port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Controller::Enter() -> void {
|
auto Controller::Enter() -> void {
|
||||||
if(co_active() == input.port1->thread) input.port1->enter();
|
if(co_active() == device.controllerPort1->thread) device.controllerPort1->enter();
|
||||||
if(co_active() == input.port2->thread) input.port2->enter();
|
if(co_active() == device.controllerPort2->thread) device.controllerPort2->enter();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Controller::enter() -> void {
|
auto Controller::enter() -> void {
|
||||||
|
|
|
@ -11,7 +11,7 @@ Gamepad::Gamepad(bool port) : Controller(port) {
|
||||||
|
|
||||||
auto Gamepad::data() -> uint2 {
|
auto Gamepad::data() -> uint2 {
|
||||||
if(counter >= 16) return 1;
|
if(counter >= 16) return 1;
|
||||||
if(latched == 1) return interface->inputPoll(port, (unsigned)Input::Device::Joypad, (unsigned)Input::JoypadID::B);
|
if(latched == 1) return interface->inputPoll(port, (unsigned)Device::ID::Gamepad, B);
|
||||||
|
|
||||||
//note: D-pad physically prevents up+down and left+right from being pressed at the same time
|
//note: D-pad physically prevents up+down and left+right from being pressed at the same time
|
||||||
switch(counter++) {
|
switch(counter++) {
|
||||||
|
@ -38,19 +38,19 @@ auto Gamepad::latch(bool data) -> void {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
if(latched == 0) {
|
if(latched == 0) {
|
||||||
unsigned id = (unsigned)Input::Device::Joypad;
|
auto id = (unsigned)Device::ID::Gamepad;
|
||||||
b = interface->inputPoll(port, id, 0);
|
b = interface->inputPoll(port, id, B);
|
||||||
y = interface->inputPoll(port, id, 1);
|
y = interface->inputPoll(port, id, Y);
|
||||||
select = interface->inputPoll(port, id, 2);
|
select = interface->inputPoll(port, id, Select);
|
||||||
start = interface->inputPoll(port, id, 3);
|
start = interface->inputPoll(port, id, Start);
|
||||||
up = interface->inputPoll(port, id, 4);
|
up = interface->inputPoll(port, id, Up);
|
||||||
down = interface->inputPoll(port, id, 5);
|
down = interface->inputPoll(port, id, Down);
|
||||||
left = interface->inputPoll(port, id, 6);
|
left = interface->inputPoll(port, id, Left);
|
||||||
right = interface->inputPoll(port, id, 7);
|
right = interface->inputPoll(port, id, Right);
|
||||||
a = interface->inputPoll(port, id, 8);
|
a = interface->inputPoll(port, id, A);
|
||||||
x = interface->inputPoll(port, id, 9);
|
x = interface->inputPoll(port, id, X);
|
||||||
l = interface->inputPoll(port, id, 10);
|
l = interface->inputPoll(port, id, L);
|
||||||
r = interface->inputPoll(port, id, 11);
|
r = interface->inputPoll(port, id, R);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
struct Gamepad : Controller {
|
struct Gamepad : Controller {
|
||||||
|
enum : uint {
|
||||||
|
B, Y, Select, Start, Up, Down, Left, Right, A, X, L, R,
|
||||||
|
};
|
||||||
|
|
||||||
Gamepad(bool port);
|
Gamepad(bool port);
|
||||||
|
|
||||||
auto data() -> uint2;
|
auto data() -> uint2;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
Justifier::Justifier(bool port, bool chained):
|
Justifier::Justifier(bool port, bool chained):
|
||||||
Controller(port),
|
Controller(port),
|
||||||
chained(chained),
|
chained(chained),
|
||||||
device(chained == false ? (unsigned)Input::Device::Justifier : (unsigned)Input::Device::Justifiers)
|
device(chained == false ? (unsigned)Device::ID::Justifier : (unsigned)Device::ID::Justifiers)
|
||||||
{
|
{
|
||||||
create(Controller::Enter, 21477272);
|
create(Controller::Enter, 21477272);
|
||||||
latched = 0;
|
latched = 0;
|
||||||
|
@ -47,8 +47,8 @@ auto Justifier::enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(next < prev) {
|
if(next < prev) {
|
||||||
int nx1 = interface->inputPoll(port, device, 0 + (unsigned)Input::JustifierID::X);
|
int nx1 = interface->inputPoll(port, device, 0 + X);
|
||||||
int ny1 = interface->inputPoll(port, device, 0 + (unsigned)Input::JustifierID::Y);
|
int ny1 = interface->inputPoll(port, device, 0 + Y);
|
||||||
nx1 += player1.x;
|
nx1 += player1.x;
|
||||||
ny1 += player1.y;
|
ny1 += player1.y;
|
||||||
player1.x = max(-16, min(256 + 16, nx1));
|
player1.x = max(-16, min(256 + 16, nx1));
|
||||||
|
@ -56,8 +56,8 @@ auto Justifier::enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(next < prev && chained) {
|
if(next < prev && chained) {
|
||||||
int nx2 = interface->inputPoll(port, device, 4 + (unsigned)Input::JustifierID::X);
|
int nx2 = interface->inputPoll(port, device, 4 + X);
|
||||||
int ny2 = interface->inputPoll(port, device, 4 + (unsigned)Input::JustifierID::Y);
|
int ny2 = interface->inputPoll(port, device, 4 + Y);
|
||||||
nx2 += player2.x;
|
nx2 += player2.x;
|
||||||
ny2 += player2.y;
|
ny2 += player2.y;
|
||||||
player2.x = max(-16, min(256 + 16, nx2));
|
player2.x = max(-16, min(256 + 16, nx2));
|
||||||
|
@ -73,13 +73,13 @@ auto Justifier::data() -> uint2 {
|
||||||
if(counter >= 32) return 1;
|
if(counter >= 32) return 1;
|
||||||
|
|
||||||
if(counter == 0) {
|
if(counter == 0) {
|
||||||
player1.trigger = interface->inputPoll(port, device, 0 + (unsigned)Input::JustifierID::Trigger);
|
player1.trigger = interface->inputPoll(port, device, 0 + Trigger);
|
||||||
player1.start = interface->inputPoll(port, device, 0 + (unsigned)Input::JustifierID::Start);
|
player1.start = interface->inputPoll(port, device, 0 + Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(counter == 0 && chained) {
|
if(counter == 0 && chained) {
|
||||||
player2.trigger = interface->inputPoll(port, device, 4 + (unsigned)Input::JustifierID::Trigger);
|
player2.trigger = interface->inputPoll(port, device, 4 + Trigger);
|
||||||
player2.start = interface->inputPoll(port, device, 4 + (unsigned)Input::JustifierID::Start);
|
player2.start = interface->inputPoll(port, device, 4 + Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(counter++) {
|
switch(counter++) {
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
struct Justifier : Controller {
|
struct Justifier : Controller {
|
||||||
|
enum : uint {
|
||||||
|
X, Y, Trigger, Start,
|
||||||
|
};
|
||||||
|
|
||||||
Justifier(bool port, bool chained);
|
Justifier(bool port, bool chained);
|
||||||
|
|
||||||
auto enter() -> void;
|
auto enter() -> void;
|
||||||
|
|
|
@ -66,10 +66,10 @@ auto Mouse::latch(bool data) -> void {
|
||||||
latched = data;
|
latched = data;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
x = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
|
x = interface->inputPoll(port, (unsigned)Device::ID::Mouse, X); //-n = left, 0 = center, +n = right
|
||||||
y = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
|
y = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Y); //-n = up, 0 = center, +n = down
|
||||||
l = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Left );
|
l = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Left);
|
||||||
r = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Right);
|
r = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Right);
|
||||||
|
|
||||||
dx = x < 0; //0 = right, 1 = left
|
dx = x < 0; //0 = right, 1 = left
|
||||||
dy = y < 0; //0 = down, 1 = up
|
dy = y < 0; //0 = down, 1 = up
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
struct Mouse : Controller {
|
struct Mouse : Controller {
|
||||||
|
enum : uint {
|
||||||
|
X, Y, Left, Right,
|
||||||
|
};
|
||||||
|
|
||||||
Mouse(bool port);
|
Mouse(bool port);
|
||||||
|
|
||||||
auto data() -> uint2;
|
auto data() -> uint2;
|
||||||
|
|
|
@ -26,8 +26,8 @@ auto Multitap::data() -> uint2 {
|
||||||
port2 = 3; //controller 4
|
port2 = 3; //controller 4
|
||||||
}
|
}
|
||||||
|
|
||||||
bool data1 = interface->inputPoll(port, (unsigned)Input::Device::Multitap, port1 * 12 + index);
|
bool data1 = interface->inputPoll(port, (unsigned)Device::ID::Multitap, port1 * 12 + index);
|
||||||
bool data2 = interface->inputPoll(port, (unsigned)Input::Device::Multitap, port2 * 12 + index);
|
bool data2 = interface->inputPoll(port, (unsigned)Device::ID::Multitap, port2 * 12 + index);
|
||||||
return (data2 << 1) | (data1 << 0);
|
return (data2 << 1) | (data1 << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,8 +48,8 @@ auto SuperScope::enter() -> void {
|
||||||
|
|
||||||
if(next < prev) {
|
if(next < prev) {
|
||||||
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
|
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
|
||||||
int nx = interface->inputPoll(port, (unsigned)Input::Device::SuperScope, (unsigned)Input::SuperScopeID::X);
|
int nx = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, X);
|
||||||
int ny = interface->inputPoll(port, (unsigned)Input::Device::SuperScope, (unsigned)Input::SuperScopeID::Y);
|
int ny = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Y);
|
||||||
nx += x;
|
nx += x;
|
||||||
ny += y;
|
ny += y;
|
||||||
x = max(-16, min(256 + 16, nx));
|
x = max(-16, min(256 + 16, nx));
|
||||||
|
@ -67,7 +67,7 @@ auto SuperScope::data() -> uint2 {
|
||||||
|
|
||||||
if(counter == 0) {
|
if(counter == 0) {
|
||||||
//turbo is a switch; toggle is edge sensitive
|
//turbo is a switch; toggle is edge sensitive
|
||||||
bool newturbo = interface->inputPoll(port, (unsigned)Input::Device::SuperScope, (unsigned)Input::SuperScopeID::Turbo);
|
bool newturbo = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Turbo);
|
||||||
if(newturbo && !turbo) {
|
if(newturbo && !turbo) {
|
||||||
turbo = !turbo; //toggle state
|
turbo = !turbo; //toggle state
|
||||||
turbolock = true;
|
turbolock = true;
|
||||||
|
@ -78,7 +78,7 @@ auto SuperScope::data() -> uint2 {
|
||||||
//trigger is a button
|
//trigger is a button
|
||||||
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
||||||
trigger = false;
|
trigger = false;
|
||||||
bool newtrigger = interface->inputPoll(port, (unsigned)Input::Device::SuperScope, (unsigned)Input::SuperScopeID::Trigger);
|
bool newtrigger = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Trigger);
|
||||||
if(newtrigger && (turbo || !triggerlock)) {
|
if(newtrigger && (turbo || !triggerlock)) {
|
||||||
trigger = true;
|
trigger = true;
|
||||||
triggerlock = true;
|
triggerlock = true;
|
||||||
|
@ -87,11 +87,11 @@ auto SuperScope::data() -> uint2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
//cursor is a button; it is always level sensitive
|
//cursor is a button; it is always level sensitive
|
||||||
cursor = interface->inputPoll(port, (unsigned)Input::Device::SuperScope, (unsigned)Input::SuperScopeID::Cursor);
|
cursor = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Cursor);
|
||||||
|
|
||||||
//pause is a button; it is always edge sensitive
|
//pause is a button; it is always edge sensitive
|
||||||
pause = false;
|
pause = false;
|
||||||
bool newpause = interface->inputPoll(port, (unsigned)Input::Device::SuperScope, (unsigned)Input::SuperScopeID::Pause);
|
bool newpause = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Pause);
|
||||||
if(newpause && !pauselock) {
|
if(newpause && !pauselock) {
|
||||||
pause = true;
|
pause = true;
|
||||||
pauselock = true;
|
pauselock = true;
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
struct SuperScope : Controller {
|
struct SuperScope : Controller {
|
||||||
|
enum : uint {
|
||||||
|
X, Y, Trigger, Cursor, Turbo, Pause,
|
||||||
|
};
|
||||||
|
|
||||||
SuperScope(bool port);
|
SuperScope(bool port);
|
||||||
|
|
||||||
auto enter() -> void;
|
auto enter() -> void;
|
||||||
|
|
|
@ -26,7 +26,7 @@ USART::USART(bool port) : Controller(port) {
|
||||||
txlength = 0;
|
txlength = 0;
|
||||||
txdata = 0;
|
txdata = 0;
|
||||||
|
|
||||||
string filename = {interface->path(ID::SuperFamicom), "usart.so"};
|
string filename{interface->path(ID::SuperFamicom), "usart.so"};
|
||||||
if(openAbsolute(filename)) {
|
if(openAbsolute(filename)) {
|
||||||
init = sym("usart_init");
|
init = sym("usart_init");
|
||||||
main = sym("usart_main");
|
main = sym("usart_main");
|
||||||
|
@ -93,7 +93,7 @@ auto USART::data() -> uint2 {
|
||||||
if(iobit()) {
|
if(iobit()) {
|
||||||
if(counter >= 16) return 1;
|
if(counter >= 16) return 1;
|
||||||
uint2 result = 0;
|
uint2 result = 0;
|
||||||
if(counter < 12) result = interface->inputPoll(port, (unsigned)Input::Device::Joypad, counter);
|
if(counter < 12) result = interface->inputPoll(port, (unsigned)Device::ID::Gamepad, counter);
|
||||||
if(latched == 0) counter++;
|
if(latched == 0) counter++;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ void CPU::step(unsigned clocks) {
|
||||||
auto& chip = *coprocessors[i];
|
auto& chip = *coprocessors[i];
|
||||||
chip.clock -= clocks * (uint64)chip.frequency;
|
chip.clock -= clocks * (uint64)chip.frequency;
|
||||||
}
|
}
|
||||||
input.port1->clock -= clocks * (uint64)input.port1->frequency;
|
device.controllerPort1->clock -= clocks * (uint64)device.controllerPort1->frequency;
|
||||||
input.port2->clock -= clocks * (uint64)input.port2->frequency;
|
device.controllerPort2->clock -= clocks * (uint64)device.controllerPort2->frequency;
|
||||||
synchronize_controllers();
|
synchronize_controllers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ void CPU::synchronize_coprocessors() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::synchronize_controllers() {
|
void CPU::synchronize_controllers() {
|
||||||
if(input.port1->clock < 0) co_switch(input.port1->thread);
|
if(device.controllerPort1->clock < 0) co_switch(device.controllerPort1->thread);
|
||||||
if(input.port2->clock < 0) co_switch(input.port2->thread);
|
if(device.controllerPort2->clock < 0) co_switch(device.controllerPort2->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Enter() { cpu.enter(); }
|
void CPU::Enter() { cpu.enter(); }
|
||||||
|
@ -125,7 +125,7 @@ void CPU::power() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::reset() {
|
void CPU::reset() {
|
||||||
create(Enter, system.cpu_frequency());
|
create(Enter, system.cpuFrequency());
|
||||||
coprocessors.reset();
|
coprocessors.reset();
|
||||||
PPUcounter::reset();
|
PPUcounter::reset();
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,8 @@ void CPU::mmio_w2183(uint8 data) {
|
||||||
//strobing $4016.d0 affects both controller port latches.
|
//strobing $4016.d0 affects both controller port latches.
|
||||||
//$4017 bit 0 writes are ignored.
|
//$4017 bit 0 writes are ignored.
|
||||||
void CPU::mmio_w4016(uint8 data) {
|
void CPU::mmio_w4016(uint8 data) {
|
||||||
input.port1->latch(data & 1);
|
device.controllerPort1->latch(data & 1);
|
||||||
input.port2->latch(data & 1);
|
device.controllerPort2->latch(data & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//JOYSER0
|
//JOYSER0
|
||||||
|
@ -42,7 +42,7 @@ void CPU::mmio_w4016(uint8 data) {
|
||||||
//1-0 = Joypad serial data
|
//1-0 = Joypad serial data
|
||||||
uint8 CPU::mmio_r4016() {
|
uint8 CPU::mmio_r4016() {
|
||||||
uint8 r = regs.mdr & 0xfc;
|
uint8 r = regs.mdr & 0xfc;
|
||||||
r |= input.port1->data();
|
r |= device.controllerPort1->data();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ uint8 CPU::mmio_r4016() {
|
||||||
//1-0 = Joypad serial data
|
//1-0 = Joypad serial data
|
||||||
uint8 CPU::mmio_r4017() {
|
uint8 CPU::mmio_r4017() {
|
||||||
uint8 r = (regs.mdr & 0xe0) | 0x1c;
|
uint8 r = (regs.mdr & 0xe0) | 0x1c;
|
||||||
r |= input.port2->data();
|
r |= device.controllerPort2->data();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +408,7 @@ uint8 CPU::mmio_read(unsigned addr) {
|
||||||
//APU
|
//APU
|
||||||
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
|
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
|
||||||
synchronize_smp();
|
synchronize_smp();
|
||||||
return smp.port_read(addr);
|
return smp.portRead(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//DMA
|
//DMA
|
||||||
|
|
|
@ -9,14 +9,14 @@ void CPU::step_auto_joypad_poll() {
|
||||||
|
|
||||||
if(status.auto_joypad_active && status.auto_joypad_latch) {
|
if(status.auto_joypad_active && status.auto_joypad_latch) {
|
||||||
if(status.auto_joypad_counter == 0) {
|
if(status.auto_joypad_counter == 0) {
|
||||||
input.port1->latch(1);
|
device.controllerPort1->latch(1);
|
||||||
input.port2->latch(1);
|
device.controllerPort2->latch(1);
|
||||||
input.port1->latch(0);
|
device.controllerPort1->latch(0);
|
||||||
input.port2->latch(0);
|
device.controllerPort2->latch(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint2 port0 = input.port1->data();
|
uint2 port0 = device.controllerPort1->data();
|
||||||
uint2 port1 = input.port2->data();
|
uint2 port1 = device.controllerPort2->data();
|
||||||
|
|
||||||
status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
|
status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
|
||||||
status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
|
status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
|
||||||
|
|
|
@ -287,7 +287,7 @@ auto DSP::power() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DSP::reset() -> void {
|
auto DSP::reset() -> void {
|
||||||
create(Enter, system.apu_frequency());
|
create(Enter, system.apuFrequency());
|
||||||
|
|
||||||
REG(FLG) = 0xe0;
|
REG(FLG) = 0xe0;
|
||||||
state.noise = 0x4000;
|
state.noise = 0x4000;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//Sony CXD1222Q-1
|
||||||
|
|
||||||
struct DSP : Thread {
|
struct DSP : Thread {
|
||||||
enum : bool { Threaded = true };
|
enum : bool { Threaded = true };
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <sfc/sfc.hpp>
|
||||||
|
|
||||||
|
#define EBOOT_CPP
|
||||||
|
namespace SuperFamicom {
|
||||||
|
|
||||||
|
eBoot eboot;
|
||||||
|
|
||||||
|
auto eBoot::init() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eBoot::load() -> void {
|
||||||
|
resetVector = bus.read(0xfffc) << 0;
|
||||||
|
resetVector |= bus.read(0xfffd) << 8;
|
||||||
|
|
||||||
|
for(auto& byte : ram) byte = 0xdb;
|
||||||
|
ram[0] = 0x6c; //jmp ($fffc)
|
||||||
|
ram[1] = 0xfc;
|
||||||
|
ram[2] = 0xff;
|
||||||
|
|
||||||
|
bus.map({&eBoot::read, &eboot}, {&eBoot::write, &eboot}, 0x00, 0x00, 0xfffc, 0xfffd);
|
||||||
|
bus.map({&eBoot::read, &eboot}, {&eBoot::write, &eboot}, 0x00, 0x3f, 0x2184, 0x21ff);
|
||||||
|
bus.map({&eBoot::read, &eboot}, {&eBoot::write, &eboot}, 0x80, 0xbf, 0x2184, 0x21ff);
|
||||||
|
|
||||||
|
if(auto buffer = file::read({interface->path(ID::System), "eboot.rom"})) {
|
||||||
|
memory::copy(ram, sizeof(ram), buffer.data(), buffer.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eBoot::unload() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eBoot::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eBoot::reset() -> void {
|
||||||
|
booted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eBoot::read(uint addr) -> uint8 {
|
||||||
|
addr &= 0xffff;
|
||||||
|
if(addr == 0xfffc) return booted ? resetVector >> 0 : 0x84;
|
||||||
|
if(addr == 0xfffd) return booted ? resetVector >> 8 : (booted = true, 0x21);
|
||||||
|
if(addr >= 0x2184 && addr <= 0x21ff) return ram[addr - 0x2184];
|
||||||
|
return 0xdb; //should never occur
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eBoot::write(uint addr, uint8 data) -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
struct eBoot : Memory {
|
||||||
|
auto init() -> void;
|
||||||
|
auto load() -> void;
|
||||||
|
auto unload() -> void;
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
|
|
||||||
|
auto read(uint addr) -> uint8;
|
||||||
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool booted = false;
|
||||||
|
uint16 resetVector = 0;
|
||||||
|
uint8 ram[124] = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern eBoot eboot;
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include <sfc/expansion/eboot/eboot.hpp>
|
||||||
|
#include <sfc/expansion/satellaview/satellaview.hpp>
|
|
@ -1,6 +1,6 @@
|
||||||
#include <sfc/sfc.hpp>
|
#include <sfc/sfc.hpp>
|
||||||
|
|
||||||
#define SATELLAVIEW_BASE_UNIT_CPP
|
#define SATELLAVIEW_EXPANSION_CPP
|
||||||
namespace SuperFamicom {
|
namespace SuperFamicom {
|
||||||
|
|
||||||
SatellaviewBaseUnit satellaviewbaseunit;
|
SatellaviewBaseUnit satellaviewbaseunit;
|
|
@ -22,7 +22,11 @@ Interface::Interface() {
|
||||||
media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", false});
|
media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", false});
|
||||||
media.append({ID::SuperFamicom, "Sufami Turbo", "st", false});
|
media.append({ID::SuperFamicom, "Sufami Turbo", "st", false});
|
||||||
|
|
||||||
{ Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
{ Device device{0, ID::ControllerPort1 | ID::ControllerPort2 | ID::ExpansionPort, "None"};
|
||||||
|
this->device.append(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Device device{1, ID::ControllerPort1 | ID::ControllerPort2, "Gamepad"};
|
||||||
device.input.append({ 0, 0, "B" });
|
device.input.append({ 0, 0, "B" });
|
||||||
device.input.append({ 1, 0, "Y" });
|
device.input.append({ 1, 0, "Y" });
|
||||||
device.input.append({ 2, 0, "Select"});
|
device.input.append({ 2, 0, "Select"});
|
||||||
|
@ -39,7 +43,7 @@ Interface::Interface() {
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ Device device{1, ID::Port1 | ID::Port2, "Multitap"};
|
{ Device device{2, ID::ControllerPort1 | ID::ControllerPort2, "Multitap"};
|
||||||
for(unsigned p = 1, n = 0; p <= 4; p++, n += 12) {
|
for(unsigned p = 1, n = 0; p <= 4; p++, n += 12) {
|
||||||
device.input.append({n + 0, 0, {"Port ", p, " - ", "B" }});
|
device.input.append({n + 0, 0, {"Port ", p, " - ", "B" }});
|
||||||
device.input.append({n + 1, 0, {"Port ", p, " - ", "Y" }});
|
device.input.append({n + 1, 0, {"Port ", p, " - ", "Y" }});
|
||||||
|
@ -59,7 +63,7 @@ Interface::Interface() {
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ Device device{2, ID::Port1 | ID::Port2, "Mouse"};
|
{ Device device{3, ID::ControllerPort1 | ID::ControllerPort2, "Mouse"};
|
||||||
device.input.append({0, 1, "X-axis"});
|
device.input.append({0, 1, "X-axis"});
|
||||||
device.input.append({1, 1, "Y-axis"});
|
device.input.append({1, 1, "Y-axis"});
|
||||||
device.input.append({2, 0, "Left" });
|
device.input.append({2, 0, "Left" });
|
||||||
|
@ -68,7 +72,7 @@ Interface::Interface() {
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ Device device{3, ID::Port2, "Super Scope"};
|
{ Device device{4, ID::ControllerPort2, "Super Scope"};
|
||||||
device.input.append({0, 1, "X-axis" });
|
device.input.append({0, 1, "X-axis" });
|
||||||
device.input.append({1, 1, "Y-axis" });
|
device.input.append({1, 1, "Y-axis" });
|
||||||
device.input.append({2, 0, "Trigger"});
|
device.input.append({2, 0, "Trigger"});
|
||||||
|
@ -79,7 +83,7 @@ Interface::Interface() {
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ Device device{4, ID::Port2, "Justifier"};
|
{ Device device{5, ID::ControllerPort2, "Justifier"};
|
||||||
device.input.append({0, 1, "X-axis" });
|
device.input.append({0, 1, "X-axis" });
|
||||||
device.input.append({1, 1, "Y-axis" });
|
device.input.append({1, 1, "Y-axis" });
|
||||||
device.input.append({2, 0, "Trigger"});
|
device.input.append({2, 0, "Trigger"});
|
||||||
|
@ -88,7 +92,7 @@ Interface::Interface() {
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ Device device{5, ID::Port2, "Justifiers"};
|
{ Device device{6, ID::ControllerPort2, "Justifiers"};
|
||||||
device.input.append({0, 1, "Port 1 - X-axis" });
|
device.input.append({0, 1, "Port 1 - X-axis" });
|
||||||
device.input.append({1, 1, "Port 1 - Y-axis" });
|
device.input.append({1, 1, "Port 1 - Y-axis" });
|
||||||
device.input.append({2, 0, "Port 1 - Trigger"});
|
device.input.append({2, 0, "Port 1 - Trigger"});
|
||||||
|
@ -102,16 +106,21 @@ Interface::Interface() {
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ Device device{6, ID::Port1, "Serial USART"};
|
{ Device device{7, ID::ControllerPort1, "Serial USART"};
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ Device device{7, ID::Port1 | ID::Port2, "None"};
|
{ Device device{8, ID::ExpansionPort, "Satellaview"};
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
port.append({0, "Port 1"});
|
{ Device device{9, ID::ExpansionPort, "eBoot"};
|
||||||
port.append({1, "Port 2"});
|
this->device.append(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
port.append({0, "Controller Port 1"});
|
||||||
|
port.append({1, "Controller Port 2"});
|
||||||
|
port.append({2, "Expansion Port"});
|
||||||
|
|
||||||
for(auto& device : this->device) {
|
for(auto& device : this->device) {
|
||||||
for(auto& port : this->port) {
|
for(auto& port : this->port) {
|
||||||
|
@ -128,13 +137,13 @@ auto Interface::title() -> string {
|
||||||
|
|
||||||
auto Interface::videoFrequency() -> double {
|
auto Interface::videoFrequency() -> double {
|
||||||
switch(system.region()) { default:
|
switch(system.region()) { default:
|
||||||
case System::Region::NTSC: return system.cpu_frequency() / (262.0 * 1364.0 - 4.0);
|
case System::Region::NTSC: return system.cpuFrequency() / (262.0 * 1364.0 - 4.0);
|
||||||
case System::Region::PAL: return system.cpu_frequency() / (312.0 * 1364.0);
|
case System::Region::PAL: return system.cpuFrequency() / (312.0 * 1364.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::audioFrequency() -> double {
|
auto Interface::audioFrequency() -> double {
|
||||||
return system.apu_frequency() / 768.0;
|
return system.apuFrequency() / 768.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::loaded() -> bool {
|
auto Interface::loaded() -> bool {
|
||||||
|
@ -396,7 +405,7 @@ auto Interface::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::connect(unsigned port, unsigned device) -> void {
|
auto Interface::connect(unsigned port, unsigned device) -> void {
|
||||||
input.connect(port, (Input::Device)device);
|
SuperFamicom::device.connect(port, (SuperFamicom::Device::ID)device);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::power() -> void {
|
auto Interface::power() -> void {
|
||||||
|
@ -423,7 +432,7 @@ auto Interface::rtcsync() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::serialize() -> serializer {
|
auto Interface::serialize() -> serializer {
|
||||||
system.runtosave();
|
system.runToSave();
|
||||||
return system.serialize();
|
return system.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,9 +83,10 @@ struct ID {
|
||||||
SufamiTurboSlotBROM,
|
SufamiTurboSlotBROM,
|
||||||
SufamiTurboSlotBRAM,
|
SufamiTurboSlotBRAM,
|
||||||
|
|
||||||
//controller ports
|
//device ports (bitmask)
|
||||||
Port1 = 1,
|
ControllerPort1 = 1,
|
||||||
Port2 = 2,
|
ControllerPort2 = 2,
|
||||||
|
ExpansionPort = 4,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ void PPU::power() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::reset() {
|
void PPU::reset() {
|
||||||
create(Enter, system.cpu_frequency());
|
create(Enter, system.cpuFrequency());
|
||||||
PPUcounter::reset();
|
PPUcounter::reset();
|
||||||
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
namespace SuperFamicom {
|
namespace SuperFamicom {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const string Name = "bsnes";
|
static const string Name = "bsnes";
|
||||||
static const unsigned SerializerVersion = 29;
|
static const uint SerializerVersion = 29;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ namespace SuperFamicom {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto create(auto (*entrypoint)() -> void, unsigned frequency) -> void {
|
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||||
this->frequency = frequency;
|
this->frequency = frequency;
|
||||||
|
@ -45,7 +45,7 @@ namespace SuperFamicom {
|
||||||
}
|
}
|
||||||
|
|
||||||
cothread_t thread = nullptr;
|
cothread_t thread = nullptr;
|
||||||
unsigned frequency = 0;
|
uint frequency = 0;
|
||||||
int64 clock = 0;
|
int64 clock = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ namespace SuperFamicom {
|
||||||
|
|
||||||
#include <sfc/controller/controller.hpp>
|
#include <sfc/controller/controller.hpp>
|
||||||
#include <sfc/system/system.hpp>
|
#include <sfc/system/system.hpp>
|
||||||
#include <sfc/base/base.hpp>
|
#include <sfc/expansion/expansion.hpp>
|
||||||
#include <sfc/chip/chip.hpp>
|
#include <sfc/chip/chip.hpp>
|
||||||
#include <sfc/slot/slot.hpp>
|
#include <sfc/slot/slot.hpp>
|
||||||
#include <sfc/cartridge/cartridge.hpp>
|
#include <sfc/cartridge/cartridge.hpp>
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
#ifdef SMP_CPP
|
#ifdef SMP_CPP
|
||||||
|
|
||||||
alwaysinline uint8 SMP::ram_read(uint16 addr) {
|
alwaysinline auto SMP::ramRead(uint16 addr) -> uint8 {
|
||||||
if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f];
|
if(addr >= 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
||||||
if(status.ram_disable) return 0x5a; //0xff on mini-SNES
|
if(status.ramDisable) return 0x5a; //0xff on mini-SNES
|
||||||
return apuram[addr];
|
return apuram[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
alwaysinline void SMP::ram_write(uint16 addr, uint8 data) {
|
alwaysinline auto SMP::ramWrite(uint16 addr, uint8 data) -> void {
|
||||||
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
|
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
|
||||||
if(status.ram_writable && !status.ram_disable) apuram[addr] = data;
|
if(status.ramWritable && !status.ramDisable) apuram[addr] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 SMP::port_read(uint2 port) const {
|
auto SMP::portRead(uint2 port) const -> uint8 {
|
||||||
return apuram[0xf4 + port];
|
return apuram[0xf4 + port];
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::port_write(uint2 port, uint8 data) {
|
auto SMP::portWrite(uint2 port, uint8 data) -> void {
|
||||||
apuram[0xf4 + port] = data;
|
apuram[0xf4 + port] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 SMP::op_busread(uint16 addr) {
|
auto SMP::busRead(uint16 addr) -> uint8 {
|
||||||
unsigned result;
|
uint result;
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0xf0: //TEST -- write-only register
|
case 0xf0: //TEST -- write-only register
|
||||||
|
@ -30,17 +30,17 @@ uint8 SMP::op_busread(uint16 addr) {
|
||||||
return 0x00;
|
return 0x00;
|
||||||
|
|
||||||
case 0xf2: //DSPADDR
|
case 0xf2: //DSPADDR
|
||||||
return status.dsp_addr;
|
return status.dspAddr;
|
||||||
|
|
||||||
case 0xf3: //DSPDATA
|
case 0xf3: //DSPDATA
|
||||||
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||||
return dsp.read(status.dsp_addr & 0x7f);
|
return dsp.read(status.dspAddr & 0x7f);
|
||||||
|
|
||||||
case 0xf4: //CPUIO0
|
case 0xf4: //CPUIO0
|
||||||
case 0xf5: //CPUIO1
|
case 0xf5: //CPUIO1
|
||||||
case 0xf6: //CPUIO2
|
case 0xf6: //CPUIO2
|
||||||
case 0xf7: //CPUIO3
|
case 0xf7: //CPUIO3
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return cpu.port_read(addr);
|
return cpu.port_read(addr);
|
||||||
|
|
||||||
case 0xf8: //RAM0
|
case 0xf8: //RAM0
|
||||||
|
@ -55,50 +55,50 @@ uint8 SMP::op_busread(uint16 addr) {
|
||||||
return 0x00;
|
return 0x00;
|
||||||
|
|
||||||
case 0xfd: //T0OUT -- 4-bit counter value
|
case 0xfd: //T0OUT -- 4-bit counter value
|
||||||
result = timer0.stage3_ticks;
|
result = timer0.stage3;
|
||||||
timer0.stage3_ticks = 0;
|
timer0.stage3 = 0;
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
case 0xfe: //T1OUT -- 4-bit counter value
|
case 0xfe: //T1OUT -- 4-bit counter value
|
||||||
result = timer1.stage3_ticks;
|
result = timer1.stage3;
|
||||||
timer1.stage3_ticks = 0;
|
timer1.stage3 = 0;
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
case 0xff: //T2OUT -- 4-bit counter value
|
case 0xff: //T2OUT -- 4-bit counter value
|
||||||
result = timer2.stage3_ticks;
|
result = timer2.stage3;
|
||||||
timer2.stage3_ticks = 0;
|
timer2.stage3 = 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ram_read(addr);
|
return ramRead(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::op_buswrite(uint16 addr, uint8 data) {
|
auto SMP::busWrite(uint16 addr, uint8 data) -> void {
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0xf0: //TEST
|
case 0xf0: //TEST
|
||||||
if(regs.p.p) break; //writes only valid when P flag is clear
|
if(regs.p.p) break; //writes only valid when P flag is clear
|
||||||
|
|
||||||
status.clock_speed = (data >> 6) & 3;
|
status.clockSpeed = (data >> 6) & 3;
|
||||||
status.timer_speed = (data >> 4) & 3;
|
status.timerSpeed = (data >> 4) & 3;
|
||||||
status.timers_enable = data & 0x08;
|
status.timersEnable = data & 0x08;
|
||||||
status.ram_disable = data & 0x04;
|
status.ramDisable = data & 0x04;
|
||||||
status.ram_writable = data & 0x02;
|
status.ramWritable = data & 0x02;
|
||||||
status.timers_disable = data & 0x01;
|
status.timersDisable = data & 0x01;
|
||||||
|
|
||||||
status.timer_step = (1 << status.clock_speed) + (2 << status.timer_speed);
|
status.timerStep = (1 << status.clockSpeed) + (2 << status.timerSpeed);
|
||||||
|
|
||||||
timer0.synchronize_stage1();
|
timer0.synchronizeStage1();
|
||||||
timer1.synchronize_stage1();
|
timer1.synchronizeStage1();
|
||||||
timer2.synchronize_stage1();
|
timer2.synchronizeStage1();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf1: //CONTROL
|
case 0xf1: //CONTROL
|
||||||
status.iplrom_enable = data & 0x80;
|
status.iplromEnable = data & 0x80;
|
||||||
|
|
||||||
if(data & 0x30) {
|
if(data & 0x30) {
|
||||||
//one-time clearing of APU port read registers,
|
//one-time clearing of APU port read registers,
|
||||||
//emulated by simulating CPU writes of 0x00
|
//emulated by simulating CPU writes of 0x00
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
if(data & 0x20) {
|
if(data & 0x20) {
|
||||||
cpu.port_write(2, 0x00);
|
cpu.port_write(2, 0x00);
|
||||||
cpu.port_write(3, 0x00);
|
cpu.port_write(3, 0x00);
|
||||||
|
@ -110,40 +110,40 @@ void SMP::op_buswrite(uint16 addr, uint8 data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//0->1 transistion resets timers
|
//0->1 transistion resets timers
|
||||||
if(timer2.enable == false && (data & 0x04)) {
|
if(!timer2.enable && (data & 0x04)) {
|
||||||
timer2.stage2_ticks = 0;
|
timer2.stage2 = 0;
|
||||||
timer2.stage3_ticks = 0;
|
timer2.stage3 = 0;
|
||||||
}
|
}
|
||||||
timer2.enable = data & 0x04;
|
timer2.enable = data & 0x04;
|
||||||
|
|
||||||
if(timer1.enable == false && (data & 0x02)) {
|
if(!timer1.enable && (data & 0x02)) {
|
||||||
timer1.stage2_ticks = 0;
|
timer1.stage2 = 0;
|
||||||
timer1.stage3_ticks = 0;
|
timer1.stage3 = 0;
|
||||||
}
|
}
|
||||||
timer1.enable = data & 0x02;
|
timer1.enable = data & 0x02;
|
||||||
|
|
||||||
if(timer0.enable == false && (data & 0x01)) {
|
if(!timer0.enable && (data & 0x01)) {
|
||||||
timer0.stage2_ticks = 0;
|
timer0.stage2 = 0;
|
||||||
timer0.stage3_ticks = 0;
|
timer0.stage3 = 0;
|
||||||
}
|
}
|
||||||
timer0.enable = data & 0x01;
|
timer0.enable = data & 0x01;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf2: //DSPADDR
|
case 0xf2: //DSPADDR
|
||||||
status.dsp_addr = data;
|
status.dspAddr = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf3: //DSPDATA
|
case 0xf3: //DSPDATA
|
||||||
if(status.dsp_addr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
if(status.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||||
dsp.write(status.dsp_addr & 0x7f, data);
|
dsp.write(status.dspAddr & 0x7f, data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf4: //CPUIO0
|
case 0xf4: //CPUIO0
|
||||||
case 0xf5: //CPUIO1
|
case 0xf5: //CPUIO1
|
||||||
case 0xf6: //CPUIO2
|
case 0xf6: //CPUIO2
|
||||||
case 0xf7: //CPUIO3
|
case 0xf7: //CPUIO3
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
port_write(addr, data);
|
portWrite(addr, data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf8: //RAM0
|
case 0xf8: //RAM0
|
||||||
|
@ -172,33 +172,33 @@ void SMP::op_buswrite(uint16 addr, uint8 data) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ram_write(addr, data); //all writes, even to MMIO registers, appear on bus
|
ramWrite(addr, data); //all writes, even to MMIO registers, appear on bus
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::op_io() {
|
auto SMP::op_io() -> void {
|
||||||
add_clocks(24);
|
addClocks(24);
|
||||||
cycle_edge();
|
cycleEdge();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 SMP::op_read(uint16 addr) {
|
auto SMP::op_read(uint16 addr) -> uint8 {
|
||||||
add_clocks(12);
|
addClocks(12);
|
||||||
uint8 data = op_busread(addr);
|
uint8 data = busRead(addr);
|
||||||
add_clocks(12);
|
addClocks(12);
|
||||||
cycle_edge();
|
cycleEdge();
|
||||||
debugger.op_read(addr, data);
|
debugger.op_read(addr, data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::op_write(uint16 addr, uint8 data) {
|
auto SMP::op_write(uint16 addr, uint8 data) -> void {
|
||||||
add_clocks(24);
|
addClocks(24);
|
||||||
op_buswrite(addr, data);
|
busWrite(addr, data);
|
||||||
cycle_edge();
|
cycleEdge();
|
||||||
debugger.op_write(addr, data);
|
debugger.op_write(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 SMP::disassembler_read(uint16 addr) {
|
auto SMP::disassembler_read(uint16 addr) -> uint8 {
|
||||||
if((addr & 0xfff0) == 0x00f0) return 0x00;
|
if((addr & 0xfff0) == 0x00f0) return 0x00;
|
||||||
if((addr & 0xffc0) == 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f];
|
if((addr & 0xffc0) == 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
||||||
return apuram[addr];
|
return apuram[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,50 +1,50 @@
|
||||||
#ifdef SMP_CPP
|
#ifdef SMP_CPP
|
||||||
|
|
||||||
void SMP::serialize(serializer& s) {
|
auto SMP::serialize(serializer& s) -> void {
|
||||||
SPC700::serialize(s);
|
SPC700::serialize(s);
|
||||||
Thread::serialize(s);
|
Thread::serialize(s);
|
||||||
|
|
||||||
s.array(apuram);
|
s.array(apuram);
|
||||||
|
|
||||||
s.integer(status.clock_counter);
|
s.integer(status.clockCounter);
|
||||||
s.integer(status.dsp_counter);
|
s.integer(status.dspCounter);
|
||||||
s.integer(status.timer_step);
|
s.integer(status.timerStep);
|
||||||
|
|
||||||
s.integer(status.clock_speed);
|
s.integer(status.clockSpeed);
|
||||||
s.integer(status.timer_speed);
|
s.integer(status.timerSpeed);
|
||||||
s.integer(status.timers_enable);
|
s.integer(status.timersEnable);
|
||||||
s.integer(status.ram_disable);
|
s.integer(status.ramDisable);
|
||||||
s.integer(status.ram_writable);
|
s.integer(status.ramWritable);
|
||||||
s.integer(status.timers_disable);
|
s.integer(status.timersDisable);
|
||||||
|
|
||||||
s.integer(status.iplrom_enable);
|
s.integer(status.iplromEnable);
|
||||||
|
|
||||||
s.integer(status.dsp_addr);
|
s.integer(status.dspAddr);
|
||||||
|
|
||||||
s.integer(status.ram00f8);
|
s.integer(status.ram00f8);
|
||||||
s.integer(status.ram00f9);
|
s.integer(status.ram00f9);
|
||||||
|
|
||||||
s.integer(timer0.stage0_ticks);
|
s.integer(timer0.stage0);
|
||||||
s.integer(timer0.stage1_ticks);
|
s.integer(timer0.stage1);
|
||||||
s.integer(timer0.stage2_ticks);
|
s.integer(timer0.stage2);
|
||||||
s.integer(timer0.stage3_ticks);
|
s.integer(timer0.stage3);
|
||||||
s.integer(timer0.current_line);
|
s.integer(timer0.line);
|
||||||
s.integer(timer0.enable);
|
s.integer(timer0.enable);
|
||||||
s.integer(timer0.target);
|
s.integer(timer0.target);
|
||||||
|
|
||||||
s.integer(timer1.stage0_ticks);
|
s.integer(timer1.stage0);
|
||||||
s.integer(timer1.stage1_ticks);
|
s.integer(timer1.stage1);
|
||||||
s.integer(timer1.stage2_ticks);
|
s.integer(timer1.stage2);
|
||||||
s.integer(timer1.stage3_ticks);
|
s.integer(timer1.stage3);
|
||||||
s.integer(timer1.current_line);
|
s.integer(timer1.line);
|
||||||
s.integer(timer1.enable);
|
s.integer(timer1.enable);
|
||||||
s.integer(timer1.target);
|
s.integer(timer1.target);
|
||||||
|
|
||||||
s.integer(timer2.stage0_ticks);
|
s.integer(timer2.stage0);
|
||||||
s.integer(timer2.stage1_ticks);
|
s.integer(timer2.stage1);
|
||||||
s.integer(timer2.stage2_ticks);
|
s.integer(timer2.stage2);
|
||||||
s.integer(timer2.stage3_ticks);
|
s.integer(timer2.stage3);
|
||||||
s.integer(timer2.current_line);
|
s.integer(timer2.line);
|
||||||
s.integer(timer2.enable);
|
s.integer(timer2.enable);
|
||||||
s.integer(timer2.target);
|
s.integer(timer2.target);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,30 +9,30 @@ SMP smp;
|
||||||
#include "timing.cpp"
|
#include "timing.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
void SMP::step(unsigned clocks) {
|
auto SMP::step(uint clocks) -> void {
|
||||||
clock += clocks * (uint64)cpu.frequency;
|
clock += clocks * (uint64)cpu.frequency;
|
||||||
dsp.clock -= clocks;
|
dsp.clock -= clocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::synchronize_cpu() {
|
auto SMP::synchronizeCPU() -> void {
|
||||||
if(CPU::Threaded == true) {
|
if(CPU::Threaded) {
|
||||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||||
} else {
|
} else {
|
||||||
while(clock >= 0) cpu.enter();
|
while(clock >= 0) cpu.enter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::synchronize_dsp() {
|
auto SMP::synchronizeDSP() -> void {
|
||||||
if(DSP::Threaded == true) {
|
if(DSP::Threaded) {
|
||||||
if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread);
|
if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread);
|
||||||
} else {
|
} else {
|
||||||
while(dsp.clock < 0) dsp.enter();
|
while(dsp.clock < 0) dsp.enter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::Enter() { smp.enter(); }
|
auto SMP::Enter() -> void { smp.enter(); }
|
||||||
|
|
||||||
void SMP::enter() {
|
auto SMP::enter() -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
@ -43,81 +43,75 @@ void SMP::enter() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::power() {
|
auto SMP::power() -> void {
|
||||||
//targets not initialized/changed upon reset
|
//targets not initialized/changed upon reset
|
||||||
timer0.target = 0;
|
timer0.target = 0;
|
||||||
timer1.target = 0;
|
timer1.target = 0;
|
||||||
timer2.target = 0;
|
timer2.target = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::reset() {
|
auto SMP::reset() -> void {
|
||||||
create(Enter, system.apu_frequency());
|
create(Enter, system.apuFrequency());
|
||||||
|
|
||||||
regs.pc = 0xffc0;
|
regs.pc.l = iplrom[62];
|
||||||
|
regs.pc.h = iplrom[63];
|
||||||
regs.a = 0x00;
|
regs.a = 0x00;
|
||||||
regs.x = 0x00;
|
regs.x = 0x00;
|
||||||
regs.y = 0x00;
|
regs.y = 0x00;
|
||||||
regs.s = 0xef;
|
regs.s = 0xef;
|
||||||
regs.p = 0x02;
|
regs.p = 0x02;
|
||||||
|
|
||||||
for(auto& n : apuram) n = random(0x00);
|
for(auto& byte : apuram) byte = random(0x00);
|
||||||
apuram[0x00f4] = 0x00;
|
apuram[0x00f4] = 0x00;
|
||||||
apuram[0x00f5] = 0x00;
|
apuram[0x00f5] = 0x00;
|
||||||
apuram[0x00f6] = 0x00;
|
apuram[0x00f6] = 0x00;
|
||||||
apuram[0x00f7] = 0x00;
|
apuram[0x00f7] = 0x00;
|
||||||
|
|
||||||
status.clock_counter = 0;
|
status.clockCounter = 0;
|
||||||
status.dsp_counter = 0;
|
status.dspCounter = 0;
|
||||||
status.timer_step = 3;
|
status.timerStep = 3;
|
||||||
|
|
||||||
//$00f0
|
//$00f0
|
||||||
status.clock_speed = 0;
|
status.clockSpeed = 0;
|
||||||
status.timer_speed = 0;
|
status.timerSpeed = 0;
|
||||||
status.timers_enable = true;
|
status.timersEnable = true;
|
||||||
status.ram_disable = false;
|
status.ramDisable = false;
|
||||||
status.ram_writable = true;
|
status.ramWritable = true;
|
||||||
status.timers_disable = false;
|
status.timersDisable = false;
|
||||||
|
|
||||||
//$00f1
|
//$00f1
|
||||||
status.iplrom_enable = true;
|
status.iplromEnable = true;
|
||||||
|
|
||||||
//$00f2
|
//$00f2
|
||||||
status.dsp_addr = 0x00;
|
status.dspAddr = 0x00;
|
||||||
|
|
||||||
//$00f8,$00f9
|
//$00f8,$00f9
|
||||||
status.ram00f8 = 0x00;
|
status.ram00f8 = 0x00;
|
||||||
status.ram00f9 = 0x00;
|
status.ram00f9 = 0x00;
|
||||||
|
|
||||||
timer0.stage0_ticks = 0;
|
timer0.stage0 = 0;
|
||||||
timer1.stage0_ticks = 0;
|
timer1.stage0 = 0;
|
||||||
timer2.stage0_ticks = 0;
|
timer2.stage0 = 0;
|
||||||
|
|
||||||
timer0.stage1_ticks = 0;
|
timer0.stage1 = 0;
|
||||||
timer1.stage1_ticks = 0;
|
timer1.stage1 = 0;
|
||||||
timer2.stage1_ticks = 0;
|
timer2.stage1 = 0;
|
||||||
|
|
||||||
timer0.stage2_ticks = 0;
|
timer0.stage2 = 0;
|
||||||
timer1.stage2_ticks = 0;
|
timer1.stage2 = 0;
|
||||||
timer2.stage2_ticks = 0;
|
timer2.stage2 = 0;
|
||||||
|
|
||||||
timer0.stage3_ticks = 0;
|
timer0.stage3 = 0;
|
||||||
timer1.stage3_ticks = 0;
|
timer1.stage3 = 0;
|
||||||
timer2.stage3_ticks = 0;
|
timer2.stage3 = 0;
|
||||||
|
|
||||||
timer0.current_line = 0;
|
timer0.line = 0;
|
||||||
timer1.current_line = 0;
|
timer1.line = 0;
|
||||||
timer2.current_line = 0;
|
timer2.line = 0;
|
||||||
|
|
||||||
timer0.enable = false;
|
timer0.enable = false;
|
||||||
timer1.enable = false;
|
timer1.enable = false;
|
||||||
timer2.enable = false;
|
timer2.enable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMP::SMP() {
|
|
||||||
for(auto& byte : iplrom) byte = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SMP::~SMP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,51 @@
|
||||||
|
//Sony CXP1100Q-1
|
||||||
|
|
||||||
struct SMP : Processor::SPC700, Thread {
|
struct SMP : Processor::SPC700, Thread {
|
||||||
uint8 iplrom[64];
|
|
||||||
uint8 apuram[64 * 1024];
|
|
||||||
|
|
||||||
enum : bool { Threaded = true };
|
enum : bool { Threaded = true };
|
||||||
alwaysinline void step(unsigned clocks);
|
|
||||||
alwaysinline void synchronize_cpu();
|
|
||||||
alwaysinline void synchronize_dsp();
|
|
||||||
|
|
||||||
uint8 port_read(uint2 port) const;
|
alwaysinline auto step(uint clocks) -> void;
|
||||||
void port_write(uint2 port, uint8 data);
|
alwaysinline auto synchronizeCPU() -> void;
|
||||||
|
alwaysinline auto synchronizeDSP() -> void;
|
||||||
|
|
||||||
void enter();
|
auto portRead(uint2 port) const -> uint8;
|
||||||
void power();
|
auto portWrite(uint2 port, uint8 data) -> void;
|
||||||
void reset();
|
|
||||||
|
|
||||||
void serialize(serializer&);
|
auto enter() -> void;
|
||||||
SMP();
|
auto power() -> void;
|
||||||
~SMP();
|
auto reset() -> void;
|
||||||
|
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
|
uint8 iplrom[64] = {0};
|
||||||
|
uint8 apuram[64 * 1024] = {0};
|
||||||
|
|
||||||
privileged:
|
privileged:
|
||||||
struct {
|
struct {
|
||||||
//timing
|
//timing
|
||||||
unsigned clock_counter;
|
uint clockCounter;
|
||||||
unsigned dsp_counter;
|
uint dspCounter;
|
||||||
unsigned timer_step;
|
uint timerStep;
|
||||||
|
|
||||||
//$00f0
|
//$00f0
|
||||||
uint8 clock_speed;
|
uint8 clockSpeed;
|
||||||
uint8 timer_speed;
|
uint8 timerSpeed;
|
||||||
bool timers_enable;
|
bool timersEnable;
|
||||||
bool ram_disable;
|
bool ramDisable;
|
||||||
bool ram_writable;
|
bool ramWritable;
|
||||||
bool timers_disable;
|
bool timersDisable;
|
||||||
|
|
||||||
//$00f1
|
//$00f1
|
||||||
bool iplrom_enable;
|
bool iplromEnable;
|
||||||
|
|
||||||
//$00f2
|
//$00f2
|
||||||
uint8 dsp_addr;
|
uint8 dspAddr;
|
||||||
|
|
||||||
//$00f8,$00f9
|
//$00f8,$00f9
|
||||||
uint8 ram00f8;
|
uint8 ram00f8;
|
||||||
uint8 ram00f9;
|
uint8 ram00f9;
|
||||||
} status;
|
} status;
|
||||||
|
|
||||||
static void Enter();
|
static auto Enter() -> void;
|
||||||
|
|
||||||
friend class SMPcore;
|
|
||||||
|
|
||||||
struct Debugger {
|
struct Debugger {
|
||||||
hook<void (uint16)> op_exec;
|
hook<void (uint16)> op_exec;
|
||||||
|
@ -55,39 +54,39 @@ privileged:
|
||||||
} debugger;
|
} debugger;
|
||||||
|
|
||||||
//memory.cpp
|
//memory.cpp
|
||||||
uint8 ram_read(uint16 addr);
|
auto ramRead(uint16 addr) -> uint8;
|
||||||
void ram_write(uint16 addr, uint8 data);
|
auto ramWrite(uint16 addr, uint8 data) -> void;
|
||||||
|
|
||||||
uint8 op_busread(uint16 addr);
|
auto busRead(uint16 addr) -> uint8;
|
||||||
void op_buswrite(uint16 addr, uint8 data);
|
auto busWrite(uint16 addr, uint8 data) -> void;
|
||||||
|
|
||||||
void op_io();
|
auto op_io() -> void;
|
||||||
uint8 op_read(uint16 addr);
|
auto op_read(uint16 addr) -> uint8;
|
||||||
void op_write(uint16 addr, uint8 data);
|
auto op_write(uint16 addr, uint8 data) -> void;
|
||||||
|
|
||||||
uint8 disassembler_read(uint16 addr);
|
auto disassembler_read(uint16 addr) -> uint8;
|
||||||
|
|
||||||
//timing.cpp
|
//timing.cpp
|
||||||
template<unsigned frequency>
|
template<unsigned Frequency>
|
||||||
struct Timer {
|
struct Timer {
|
||||||
uint8 stage0_ticks;
|
uint8 stage0;
|
||||||
uint8 stage1_ticks;
|
uint8 stage1;
|
||||||
uint8 stage2_ticks;
|
uint8 stage2;
|
||||||
uint4 stage3_ticks;
|
uint4 stage3;
|
||||||
bool current_line;
|
bool line;
|
||||||
bool enable;
|
bool enable;
|
||||||
uint8 target;
|
uint8 target;
|
||||||
|
|
||||||
void tick();
|
auto tick() -> void;
|
||||||
void synchronize_stage1();
|
auto synchronizeStage1() -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
Timer<192> timer0;
|
Timer<192> timer0;
|
||||||
Timer<192> timer1;
|
Timer<192> timer1;
|
||||||
Timer< 24> timer2;
|
Timer< 24> timer2;
|
||||||
|
|
||||||
alwaysinline void add_clocks(unsigned clocks);
|
alwaysinline auto addClocks(uint clocks) -> void;
|
||||||
alwaysinline void cycle_edge();
|
alwaysinline auto cycleEdge() -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SMP smp;
|
extern SMP smp;
|
||||||
|
|
|
@ -1,62 +1,62 @@
|
||||||
#ifdef SMP_CPP
|
#ifdef SMP_CPP
|
||||||
|
|
||||||
void SMP::add_clocks(unsigned clocks) {
|
auto SMP::addClocks(uint clocks) -> void {
|
||||||
step(clocks);
|
step(clocks);
|
||||||
synchronize_dsp();
|
synchronizeDSP();
|
||||||
|
|
||||||
#if defined(DEBUGGER)
|
#if defined(DEBUGGER)
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
#else
|
#else
|
||||||
//forcefully sync S-SMP to S-CPU in case chips are not communicating
|
//forcefully sync S-SMP to S-CPU in case chips are not communicating
|
||||||
//sync if S-SMP is more than 24 samples ahead of S-CPU
|
//sync if S-SMP is more than 24 samples ahead of S-CPU
|
||||||
if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu();
|
if(clock > +(768 * 24 * (int64)24000000)) synchronizeCPU();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::cycle_edge() {
|
auto SMP::cycleEdge() -> void {
|
||||||
timer0.tick();
|
timer0.tick();
|
||||||
timer1.tick();
|
timer1.tick();
|
||||||
timer2.tick();
|
timer2.tick();
|
||||||
|
|
||||||
//TEST register S-SMP speed control
|
//TEST register S-SMP speed control
|
||||||
//24 clocks have already been added for this cycle at this point
|
//24 clocks have already been added for this cycle at this point
|
||||||
switch(status.clock_speed) {
|
switch(status.clockSpeed) {
|
||||||
case 0: break; //100% speed
|
case 0: break; //100% speed
|
||||||
case 1: add_clocks(24); break; // 50% speed
|
case 1: addClocks(24); break; // 50% speed
|
||||||
case 2: while(true) add_clocks(24); // 0% speed -- locks S-SMP
|
case 2: while(true) addClocks(24); // 0% speed -- locks S-SMP
|
||||||
case 3: add_clocks(24 * 9); break; // 10% speed
|
case 3: addClocks(24 * 9); break; // 10% speed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned timer_frequency>
|
template<unsigned Frequency>
|
||||||
void SMP::Timer<timer_frequency>::tick() {
|
auto SMP::Timer<Frequency>::tick() -> void {
|
||||||
//stage 0 increment
|
//stage 0 increment
|
||||||
stage0_ticks += smp.status.timer_step;
|
stage0 += smp.status.timerStep;
|
||||||
if(stage0_ticks < timer_frequency) return;
|
if(stage0 < Frequency) return;
|
||||||
stage0_ticks -= timer_frequency;
|
stage0 -= Frequency;
|
||||||
|
|
||||||
//stage 1 increment
|
//stage 1 increment
|
||||||
stage1_ticks ^= 1;
|
stage1 ^= 1;
|
||||||
synchronize_stage1();
|
synchronizeStage1();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned timer_frequency>
|
template<unsigned Frequency>
|
||||||
void SMP::Timer<timer_frequency>::synchronize_stage1() {
|
auto SMP::Timer<Frequency>::synchronizeStage1() -> void {
|
||||||
bool new_line = stage1_ticks;
|
bool newLine = stage1;
|
||||||
if(smp.status.timers_enable == false) new_line = false;
|
if(smp.status.timersEnable == false) newLine = false;
|
||||||
if(smp.status.timers_disable == true) new_line = false;
|
if(smp.status.timersDisable == true) newLine = false;
|
||||||
|
|
||||||
bool old_line = current_line;
|
bool oldLine = line;
|
||||||
current_line = new_line;
|
line = newLine;
|
||||||
if(old_line != 1 || new_line != 0) return; //only pulse on 1->0 transition
|
if(oldLine != 1 || newLine != 0) return; //only pulse on 1->0 transition
|
||||||
|
|
||||||
//stage 2 increment
|
//stage 2 increment
|
||||||
if(enable == false) return;
|
if(enable == false) return;
|
||||||
if(++stage2_ticks != target) return;
|
if(++stage2 != target) return;
|
||||||
|
|
||||||
//stage 3 increment
|
//stage 3 increment
|
||||||
stage2_ticks = 0;
|
stage2 = 0;
|
||||||
stage3_ticks++;
|
stage3++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,7 +14,7 @@ void Audio::coprocessor_enable(bool state) {
|
||||||
void Audio::coprocessor_frequency(double input_frequency) {
|
void Audio::coprocessor_frequency(double input_frequency) {
|
||||||
dspaudio.setFrequency(input_frequency);
|
dspaudio.setFrequency(input_frequency);
|
||||||
dspaudio.setResampler(nall::DSP::ResampleEngine::Sinc);
|
dspaudio.setResampler(nall::DSP::ResampleEngine::Sinc);
|
||||||
dspaudio.setResamplerFrequency(system.apu_frequency() / 768.0);
|
dspaudio.setResamplerFrequency(system.apuFrequency() / 768.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::sample(int16 lsample, int16 rsample) {
|
void Audio::sample(int16 lsample, int16 rsample) {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifdef SYSTEM_CPP
|
||||||
|
|
||||||
|
Device device;
|
||||||
|
|
||||||
|
Device::Device() {
|
||||||
|
connect(0, ID::Gamepad);
|
||||||
|
connect(1, ID::Gamepad);
|
||||||
|
connect(2, ID::eBoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::~Device() {
|
||||||
|
if(controllerPort1) delete controllerPort1;
|
||||||
|
if(controllerPort2) delete controllerPort2;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Device::connect(uint port, Device::ID id) -> void {
|
||||||
|
if(port == 0 || port == 1) {
|
||||||
|
Controller*& controller = (port == 0 ? controllerPort1 : controllerPort2);
|
||||||
|
|
||||||
|
if(controller) {
|
||||||
|
delete controller;
|
||||||
|
controller = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(id) { default:
|
||||||
|
case ID::None: controller = new Controller(port); break;
|
||||||
|
case ID::Gamepad: controller = new Gamepad(port); break;
|
||||||
|
case ID::Multitap: controller = new Multitap(port); break;
|
||||||
|
case ID::Mouse: controller = new Mouse(port); break;
|
||||||
|
case ID::SuperScope: controller = new SuperScope(port); break;
|
||||||
|
case ID::Justifier: controller = new Justifier(port, false); break;
|
||||||
|
case ID::Justifiers: controller = new Justifier(port, true); break;
|
||||||
|
case ID::USART: controller = new USART(port); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(port) {
|
||||||
|
case 0: configuration.controllerPort1 = id; break;
|
||||||
|
case 1: configuration.controllerPort2 = id; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == 2) {
|
||||||
|
configuration.expansionPort = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,28 @@
|
||||||
|
struct Device {
|
||||||
|
enum class ID : uint {
|
||||||
|
None,
|
||||||
|
|
||||||
|
//controller port devices
|
||||||
|
Gamepad,
|
||||||
|
Multitap,
|
||||||
|
Mouse,
|
||||||
|
SuperScope,
|
||||||
|
Justifier,
|
||||||
|
Justifiers,
|
||||||
|
USART,
|
||||||
|
|
||||||
|
//expansion port devices
|
||||||
|
Satellaview,
|
||||||
|
eBoot,
|
||||||
|
};
|
||||||
|
|
||||||
|
Device();
|
||||||
|
~Device();
|
||||||
|
|
||||||
|
auto connect(uint port, Device::ID id) -> void;
|
||||||
|
|
||||||
|
Controller* controllerPort1 = nullptr;
|
||||||
|
Controller* controllerPort2 = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Device device;
|
|
@ -1,39 +0,0 @@
|
||||||
#ifdef SYSTEM_CPP
|
|
||||||
|
|
||||||
Input input;
|
|
||||||
|
|
||||||
void Input::connect(bool port, Input::Device id) {
|
|
||||||
Controller*& controller = (port == Controller::Port1 ? port1 : port2);
|
|
||||||
if(controller) {
|
|
||||||
delete controller;
|
|
||||||
controller = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(id) { default:
|
|
||||||
case Device::None: controller = new Controller(port); break;
|
|
||||||
case Device::Joypad: controller = new Gamepad(port); break;
|
|
||||||
case Device::Multitap: controller = new Multitap(port); break;
|
|
||||||
case Device::Mouse: controller = new Mouse(port); break;
|
|
||||||
case Device::SuperScope: controller = new SuperScope(port); break;
|
|
||||||
case Device::Justifier: controller = new Justifier(port, false); break;
|
|
||||||
case Device::Justifiers: controller = new Justifier(port, true); break;
|
|
||||||
case Device::USART: controller = new USART(port); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(port) {
|
|
||||||
case Controller::Port1: configuration.controller_port1 = id; break;
|
|
||||||
case Controller::Port2: configuration.controller_port2 = id; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Input::Input() {
|
|
||||||
connect(Controller::Port1, Input::Device::Joypad);
|
|
||||||
connect(Controller::Port2, Input::Device::Joypad);
|
|
||||||
}
|
|
||||||
|
|
||||||
Input::~Input() {
|
|
||||||
if(port1) delete port1;
|
|
||||||
if(port2) delete port2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,39 +0,0 @@
|
||||||
struct Input {
|
|
||||||
enum class Device : unsigned {
|
|
||||||
Joypad,
|
|
||||||
Multitap,
|
|
||||||
Mouse,
|
|
||||||
SuperScope,
|
|
||||||
Justifier,
|
|
||||||
Justifiers,
|
|
||||||
USART,
|
|
||||||
None,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class JoypadID : unsigned {
|
|
||||||
B = 0, Y = 1, Select = 2, Start = 3,
|
|
||||||
Up = 4, Down = 5, Left = 6, Right = 7,
|
|
||||||
A = 8, X = 9, L = 10, R = 11,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class MouseID : unsigned {
|
|
||||||
X = 0, Y = 1, Left = 2, Right = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SuperScopeID : unsigned {
|
|
||||||
X = 0, Y = 1, Trigger = 2, Cursor = 3, Turbo = 4, Pause = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class JustifierID : unsigned {
|
|
||||||
X = 0, Y = 1, Trigger = 2, Start = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
Controller* port1 = nullptr;
|
|
||||||
Controller* port2 = nullptr;
|
|
||||||
|
|
||||||
void connect(bool port, Input::Device id);
|
|
||||||
Input();
|
|
||||||
~Input();
|
|
||||||
};
|
|
||||||
|
|
||||||
extern Input input;
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifdef SYSTEM_CPP
|
#ifdef SYSTEM_CPP
|
||||||
|
|
||||||
serializer System::serialize() {
|
auto System::serialize() -> serializer {
|
||||||
serializer s(serialize_size);
|
serializer s(serializeSize);
|
||||||
|
|
||||||
unsigned signature = 0x31545342, version = Info::SerializerVersion;
|
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||||
char hash[64], description[512], profile[16];
|
char hash[64], description[512], profile[16];
|
||||||
memcpy(&hash, (const char*)cartridge.sha256(), 64);
|
memcpy(&hash, (const char*)cartridge.sha256(), 64);
|
||||||
memset(&description, 0, sizeof description);
|
memset(&description, 0, sizeof description);
|
||||||
|
@ -16,12 +16,12 @@ serializer System::serialize() {
|
||||||
s.array(description);
|
s.array(description);
|
||||||
s.array(profile);
|
s.array(profile);
|
||||||
|
|
||||||
serialize_all(s);
|
serializeAll(s);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::unserialize(serializer& s) {
|
auto System::unserialize(serializer& s) -> bool {
|
||||||
unsigned signature, version;
|
uint signature, version;
|
||||||
char hash[64], description[512], profile[16];
|
char hash[64], description[512], profile[16];
|
||||||
|
|
||||||
s.integer(signature);
|
s.integer(signature);
|
||||||
|
@ -35,7 +35,7 @@ bool System::unserialize(serializer& s) {
|
||||||
if(strcmp(profile, Emulator::Profile)) return false;
|
if(strcmp(profile, Emulator::Profile)) return false;
|
||||||
|
|
||||||
power();
|
power();
|
||||||
serialize_all(s);
|
serializeAll(s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,12 +43,12 @@ bool System::unserialize(serializer& s) {
|
||||||
//internal
|
//internal
|
||||||
//========
|
//========
|
||||||
|
|
||||||
void System::serialize(serializer& s) {
|
auto System::serialize(serializer& s) -> void {
|
||||||
s.integer((unsigned&)region);
|
s.integer((uint&)region);
|
||||||
s.integer((unsigned&)expansion);
|
s.integer((uint&)expansionPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::serialize_all(serializer& s) {
|
auto System::serializeAll(serializer& s) -> void {
|
||||||
cartridge.serialize(s);
|
cartridge.serialize(s);
|
||||||
system.serialize(s);
|
system.serialize(s);
|
||||||
random.serialize(s);
|
random.serialize(s);
|
||||||
|
@ -78,10 +78,10 @@ void System::serialize_all(serializer& s) {
|
||||||
//perform dry-run state save:
|
//perform dry-run state save:
|
||||||
//determines exactly how many bytes are needed to save state for this cartridge,
|
//determines exactly how many bytes are needed to save state for this cartridge,
|
||||||
//as amount varies per game (eg different RAM sizes, special chips, etc.)
|
//as amount varies per game (eg different RAM sizes, special chips, etc.)
|
||||||
void System::serialize_init() {
|
auto System::serializeInit() -> void {
|
||||||
serializer s;
|
serializer s;
|
||||||
|
|
||||||
unsigned signature = 0, version = 0;
|
uint signature = 0, version = 0;
|
||||||
char hash[64], profile[16], description[512];
|
char hash[64], profile[16], description[512];
|
||||||
|
|
||||||
s.integer(signature);
|
s.integer(signature);
|
||||||
|
@ -90,8 +90,8 @@ void System::serialize_init() {
|
||||||
s.array(profile);
|
s.array(profile);
|
||||||
s.array(description);
|
s.array(description);
|
||||||
|
|
||||||
serialize_all(s);
|
serializeAll(s);
|
||||||
serialize_size = s.size();
|
serializeSize = s.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,12 +9,17 @@ Random random;
|
||||||
|
|
||||||
#include "video.cpp"
|
#include "video.cpp"
|
||||||
#include "audio.cpp"
|
#include "audio.cpp"
|
||||||
#include "input.cpp"
|
#include "device.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
#include <sfc/scheduler/scheduler.cpp>
|
#include <sfc/scheduler/scheduler.cpp>
|
||||||
|
|
||||||
void System::run() {
|
System::System() {
|
||||||
|
region = Region::Autodetect;
|
||||||
|
expansionPort = Device::ID::eBoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto System::run() -> void {
|
||||||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||||
|
|
||||||
scheduler.enter();
|
scheduler.enter();
|
||||||
|
@ -23,35 +28,35 @@ void System::run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::runtosave() {
|
auto System::runToSave() -> void {
|
||||||
if(CPU::Threaded == true) {
|
if(CPU::Threaded == true) {
|
||||||
scheduler.sync = Scheduler::SynchronizeMode::CPU;
|
scheduler.sync = Scheduler::SynchronizeMode::CPU;
|
||||||
runthreadtosave();
|
runThreadToSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(SMP::Threaded == true) {
|
if(SMP::Threaded == true) {
|
||||||
scheduler.thread = smp.thread;
|
scheduler.thread = smp.thread;
|
||||||
runthreadtosave();
|
runThreadToSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(PPU::Threaded == true) {
|
if(PPU::Threaded == true) {
|
||||||
scheduler.thread = ppu.thread;
|
scheduler.thread = ppu.thread;
|
||||||
runthreadtosave();
|
runThreadToSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(DSP::Threaded == true) {
|
if(DSP::Threaded == true) {
|
||||||
scheduler.thread = dsp.thread;
|
scheduler.thread = dsp.thread;
|
||||||
runthreadtosave();
|
runThreadToSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
for(unsigned i = 0; i < cpu.coprocessors.size(); i++) {
|
for(unsigned i = 0; i < cpu.coprocessors.size(); i++) {
|
||||||
auto& chip = *cpu.coprocessors[i];
|
auto& chip = *cpu.coprocessors[i];
|
||||||
scheduler.thread = chip.thread;
|
scheduler.thread = chip.thread;
|
||||||
runthreadtosave();
|
runThreadToSave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::runthreadtosave() {
|
auto System::runThreadToSave() -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
scheduler.enter();
|
scheduler.enter();
|
||||||
if(scheduler.exit_reason == Scheduler::ExitReason::SynchronizeEvent) break;
|
if(scheduler.exit_reason == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||||
|
@ -61,10 +66,12 @@ void System::runthreadtosave() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::init() {
|
auto System::init() -> void {
|
||||||
assert(interface != nullptr);
|
assert(interface != nullptr);
|
||||||
|
|
||||||
|
eboot.init();
|
||||||
satellaviewbaseunit.init();
|
satellaviewbaseunit.init();
|
||||||
|
|
||||||
icd2.init();
|
icd2.init();
|
||||||
mcc.init();
|
mcc.init();
|
||||||
nss.init();
|
nss.init();
|
||||||
|
@ -80,20 +87,20 @@ void System::init() {
|
||||||
sdd1.init();
|
sdd1.init();
|
||||||
obc1.init();
|
obc1.init();
|
||||||
msu1.init();
|
msu1.init();
|
||||||
|
|
||||||
satellaviewcartridge.init();
|
satellaviewcartridge.init();
|
||||||
|
|
||||||
video.init();
|
video.init();
|
||||||
audio.init();
|
audio.init();
|
||||||
|
|
||||||
input.connect(0, configuration.controller_port1);
|
device.connect(0, configuration.controllerPort1);
|
||||||
input.connect(1, configuration.controller_port2);
|
device.connect(1, configuration.controllerPort2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::term() {
|
auto System::term() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::load() {
|
auto System::load() -> void {
|
||||||
//string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
|
||||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
|
@ -102,13 +109,12 @@ void System::load() {
|
||||||
}
|
}
|
||||||
|
|
||||||
region = configuration.region;
|
region = configuration.region;
|
||||||
expansion = configuration.expansion_port;
|
|
||||||
if(region == Region::Autodetect) {
|
if(region == Region::Autodetect) {
|
||||||
region = (cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL);
|
region = (cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL);
|
||||||
}
|
}
|
||||||
|
expansionPort = configuration.expansionPort;
|
||||||
cpu_frequency = region() == Region::NTSC ? 21477272 : 21281370;
|
cpuFrequency = region() == Region::NTSC ? 21477272 : 21281370;
|
||||||
apu_frequency = 24607104;
|
apuFrequency = 24606720;
|
||||||
|
|
||||||
audio.coprocessor_enable(false);
|
audio.coprocessor_enable(false);
|
||||||
|
|
||||||
|
@ -118,7 +124,9 @@ void System::load() {
|
||||||
cpu.enable();
|
cpu.enable();
|
||||||
ppu.enable();
|
ppu.enable();
|
||||||
|
|
||||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.load();
|
if(expansionPort() == Device::ID::Satellaview) satellaviewbaseunit.load();
|
||||||
|
if(expansionPort() == Device::ID::eBoot) eboot.load();
|
||||||
|
|
||||||
if(cartridge.hasICD2()) icd2.load();
|
if(cartridge.hasICD2()) icd2.load();
|
||||||
if(cartridge.hasMCC()) mcc.load();
|
if(cartridge.hasMCC()) mcc.load();
|
||||||
if(cartridge.hasNSSDIP()) nss.load();
|
if(cartridge.hasNSSDIP()) nss.load();
|
||||||
|
@ -138,11 +146,13 @@ void System::load() {
|
||||||
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.load();
|
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.load();
|
||||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load();
|
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load();
|
||||||
|
|
||||||
serialize_init();
|
serializeInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::unload() {
|
auto System::unload() -> void {
|
||||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.unload();
|
if(expansionPort() == Device::ID::Satellaview) satellaviewbaseunit.unload();
|
||||||
|
if(expansionPort() == Device::ID::eBoot) eboot.unload();
|
||||||
|
|
||||||
if(cartridge.hasICD2()) icd2.unload();
|
if(cartridge.hasICD2()) icd2.unload();
|
||||||
if(cartridge.hasMCC()) mcc.unload();
|
if(cartridge.hasMCC()) mcc.unload();
|
||||||
if(cartridge.hasNSSDIP()) nss.unload();
|
if(cartridge.hasNSSDIP()) nss.unload();
|
||||||
|
@ -163,15 +173,17 @@ void System::unload() {
|
||||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload();
|
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::power() {
|
auto System::power() -> void {
|
||||||
random.seed((unsigned)time(0));
|
random.seed((uint)time(0));
|
||||||
|
|
||||||
cpu.power();
|
cpu.power();
|
||||||
smp.power();
|
smp.power();
|
||||||
dsp.power();
|
dsp.power();
|
||||||
ppu.power();
|
ppu.power();
|
||||||
|
|
||||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.power();
|
if(expansionPort() == Device::ID::Satellaview) satellaviewbaseunit.power();
|
||||||
|
if(expansionPort() == Device::ID::eBoot) eboot.power();
|
||||||
|
|
||||||
if(cartridge.hasICD2()) icd2.power();
|
if(cartridge.hasICD2()) icd2.power();
|
||||||
if(cartridge.hasMCC()) mcc.power();
|
if(cartridge.hasMCC()) mcc.power();
|
||||||
if(cartridge.hasNSSDIP()) nss.power();
|
if(cartridge.hasNSSDIP()) nss.power();
|
||||||
|
@ -193,13 +205,15 @@ void System::power() {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::reset() {
|
auto System::reset() -> void {
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
smp.reset();
|
smp.reset();
|
||||||
dsp.reset();
|
dsp.reset();
|
||||||
ppu.reset();
|
ppu.reset();
|
||||||
|
|
||||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.reset();
|
if(expansionPort() == Device::ID::Satellaview) satellaviewbaseunit.reset();
|
||||||
|
if(expansionPort() == Device::ID::eBoot) eboot.reset();
|
||||||
|
|
||||||
if(cartridge.hasICD2()) icd2.reset();
|
if(cartridge.hasICD2()) icd2.reset();
|
||||||
if(cartridge.hasMCC()) mcc.reset();
|
if(cartridge.hasMCC()) mcc.reset();
|
||||||
if(cartridge.hasNSSDIP()) nss.reset();
|
if(cartridge.hasNSSDIP()) nss.reset();
|
||||||
|
@ -231,21 +245,16 @@ void System::reset() {
|
||||||
if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1);
|
if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1);
|
||||||
|
|
||||||
scheduler.init();
|
scheduler.init();
|
||||||
input.connect(0, configuration.controller_port1);
|
device.connect(0, configuration.controllerPort1);
|
||||||
input.connect(1, configuration.controller_port2);
|
device.connect(1, configuration.controllerPort2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::scanline() {
|
auto System::scanline() -> void {
|
||||||
video.scanline();
|
video.scanline();
|
||||||
if(cpu.vcounter() == 241) scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
if(cpu.vcounter() == 241) scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::frame() {
|
auto System::frame() -> void {
|
||||||
}
|
|
||||||
|
|
||||||
System::System() {
|
|
||||||
region = Region::Autodetect;
|
|
||||||
expansion = ExpansionPortDevice::Satellaview;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +1,63 @@
|
||||||
struct Interface;
|
struct Interface;
|
||||||
|
|
||||||
|
#include "video.hpp"
|
||||||
|
#include "audio.hpp"
|
||||||
|
#include "device.hpp"
|
||||||
|
|
||||||
struct System : property<System> {
|
struct System : property<System> {
|
||||||
enum class Region : unsigned { NTSC = 0, PAL = 1, Autodetect = 2 };
|
enum class Region : uint { NTSC = 0, PAL = 1, Autodetect = 2 };
|
||||||
enum class ExpansionPortDevice : unsigned { None = 0, Satellaview = 1 };
|
|
||||||
|
|
||||||
void run();
|
System();
|
||||||
void runtosave();
|
|
||||||
|
|
||||||
void init();
|
auto run() -> void;
|
||||||
void term();
|
auto runToSave() -> void;
|
||||||
void load();
|
|
||||||
void unload();
|
|
||||||
void power();
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void frame();
|
auto init() -> void;
|
||||||
void scanline();
|
auto term() -> void;
|
||||||
|
auto load() -> void;
|
||||||
|
auto unload() -> void;
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
|
|
||||||
|
auto frame() -> void;
|
||||||
|
auto scanline() -> void;
|
||||||
|
|
||||||
//return *active* system information (settings are cached upon power-on)
|
//return *active* system information (settings are cached upon power-on)
|
||||||
readonly<Region> region;
|
readonly<Region> region;
|
||||||
readonly<ExpansionPortDevice> expansion;
|
readonly<Device::ID> expansionPort;
|
||||||
readonly<unsigned> cpu_frequency;
|
|
||||||
readonly<unsigned> apu_frequency;
|
|
||||||
readonly<unsigned> serialize_size;
|
|
||||||
|
|
||||||
serializer serialize();
|
readonly<uint> cpuFrequency;
|
||||||
bool unserialize(serializer&);
|
readonly<uint> apuFrequency;
|
||||||
|
readonly<uint> serializeSize;
|
||||||
|
|
||||||
System();
|
auto serialize() -> serializer;
|
||||||
|
auto unserialize(serializer&) -> bool;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string manifest;
|
string manifest;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void runthreadtosave();
|
auto runThreadToSave() -> void;
|
||||||
|
|
||||||
void serialize(serializer&);
|
auto serialize(serializer&) -> void;
|
||||||
void serialize_all(serializer&);
|
auto serializeAll(serializer&) -> void;
|
||||||
void serialize_init();
|
auto serializeInit() -> void;
|
||||||
|
|
||||||
friend class Cartridge;
|
friend class Cartridge;
|
||||||
friend class Video;
|
friend class Video;
|
||||||
friend class Audio;
|
friend class Audio;
|
||||||
friend class Input;
|
friend class Device;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern System system;
|
extern System system;
|
||||||
|
|
||||||
#include "video.hpp"
|
|
||||||
#include "audio.hpp"
|
|
||||||
#include "input.hpp"
|
|
||||||
|
|
||||||
#include <sfc/scheduler/scheduler.hpp>
|
#include <sfc/scheduler/scheduler.hpp>
|
||||||
|
|
||||||
struct Configuration {
|
struct Configuration {
|
||||||
Input::Device controller_port1 = Input::Device::Joypad;
|
Device::ID controllerPort1 = Device::ID::Gamepad;
|
||||||
Input::Device controller_port2 = Input::Device::Joypad;
|
Device::ID controllerPort2 = Device::ID::Gamepad;
|
||||||
System::ExpansionPortDevice expansion_port = System::ExpansionPortDevice::Satellaview;
|
Device::ID expansionPort = Device::ID::eBoot;
|
||||||
System::Region region = System::Region::Autodetect;
|
System::Region region = System::Region::Autodetect;
|
||||||
bool random = true;
|
bool random = true;
|
||||||
};
|
};
|
||||||
|
@ -65,21 +65,21 @@ struct Configuration {
|
||||||
extern Configuration configuration;
|
extern Configuration configuration;
|
||||||
|
|
||||||
struct Random {
|
struct Random {
|
||||||
void seed(unsigned seed) {
|
auto seed(uint seed) -> void {
|
||||||
iter = seed;
|
iter = seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned operator()(unsigned result) {
|
auto operator()(uint result) -> uint {
|
||||||
if(configuration.random == false) return result;
|
if(configuration.random == false) return result;
|
||||||
return iter = (iter >> 1) ^ (((iter & 1) - 1) & 0xedb88320);
|
return iter = (iter >> 1) ^ (((iter & 1) - 1) & 0xedb88320);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialize(serializer& s) {
|
auto serialize(serializer& s) -> void {
|
||||||
s.integer(iter);
|
s.integer(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned iter = 0;
|
uint iter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Random random;
|
extern Random random;
|
||||||
|
|
|
@ -105,20 +105,20 @@ void Video::draw_cursor(uint16_t color, int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::update() {
|
void Video::update() {
|
||||||
switch(configuration.controller_port2) {
|
switch(configuration.controllerPort2) {
|
||||||
case Input::Device::SuperScope:
|
case Device::ID::SuperScope:
|
||||||
if(dynamic_cast<SuperScope*>(input.port2)) {
|
if(dynamic_cast<SuperScope*>(device.controllerPort2)) {
|
||||||
SuperScope &device = (SuperScope&)*input.port2;
|
SuperScope& controller = (SuperScope&)*device.controllerPort2;
|
||||||
draw_cursor(0x7c00, device.x, device.y);
|
draw_cursor(0x7c00, controller.x, controller.y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Input::Device::Justifier:
|
case Device::ID::Justifier:
|
||||||
case Input::Device::Justifiers:
|
case Device::ID::Justifiers:
|
||||||
if(dynamic_cast<Justifier*>(input.port2)) {
|
if(dynamic_cast<Justifier*>(device.controllerPort2)) {
|
||||||
Justifier &device = (Justifier&)*input.port2;
|
Justifier& controller = (Justifier&)*device.controllerPort2;
|
||||||
draw_cursor(0x001f, device.player1.x, device.player1.y);
|
draw_cursor(0x001f, controller.player1.x, controller.player1.y);
|
||||||
if(device.chained == false) break;
|
if(!controller.chained) break;
|
||||||
draw_cursor(0x02e0, device.player2.x, device.player2.y);
|
draw_cursor(0x02e0, controller.player2.x, controller.player2.y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,11 +115,12 @@ auto Presentation::updateEmulator() -> void {
|
||||||
resetSystem.setVisible(emulator->information.resettable);
|
resetSystem.setVisible(emulator->information.resettable);
|
||||||
inputPort1.setVisible(false).reset();
|
inputPort1.setVisible(false).reset();
|
||||||
inputPort2.setVisible(false).reset();
|
inputPort2.setVisible(false).reset();
|
||||||
|
inputPort3.setVisible(false).reset();
|
||||||
|
|
||||||
for(auto n : range(emulator->port)) {
|
for(auto n : range(emulator->port)) {
|
||||||
if(n >= 2) break;
|
if(n >= 3) break;
|
||||||
auto& port = emulator->port[n];
|
auto& port = emulator->port[n];
|
||||||
auto& menu = (n == 0 ? inputPort1 : inputPort2);
|
auto& menu = (n == 0 ? inputPort1 : n == 1 ? inputPort2 : inputPort3);
|
||||||
menu.setText(port.name);
|
menu.setText(port.name);
|
||||||
|
|
||||||
Group devices;
|
Group devices;
|
||||||
|
@ -133,7 +134,7 @@ auto Presentation::updateEmulator() -> void {
|
||||||
if(devices.objectCount() > 1) menu.setVisible();
|
if(devices.objectCount() > 1) menu.setVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
systemMenuSeparatorPorts.setVisible(inputPort1.visible() || inputPort2.visible());
|
systemMenuSeparatorPorts.setVisible(inputPort1.visible() || inputPort2.visible() || inputPort3.visible());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Presentation::resizeViewport() -> void {
|
auto Presentation::resizeViewport() -> void {
|
||||||
|
|
|
@ -15,6 +15,7 @@ struct Presentation : Window {
|
||||||
MenuSeparator systemMenuSeparatorPorts{&systemMenu};
|
MenuSeparator systemMenuSeparatorPorts{&systemMenu};
|
||||||
Menu inputPort1{&systemMenu};
|
Menu inputPort1{&systemMenu};
|
||||||
Menu inputPort2{&systemMenu};
|
Menu inputPort2{&systemMenu};
|
||||||
|
Menu inputPort3{&systemMenu};
|
||||||
MenuSeparator systemMenuSeparatorUnload{&systemMenu};
|
MenuSeparator systemMenuSeparatorUnload{&systemMenu};
|
||||||
MenuItem unloadSystem{&systemMenu};
|
MenuItem unloadSystem{&systemMenu};
|
||||||
Menu settingsMenu{&menuBar};
|
Menu settingsMenu{&menuBar};
|
||||||
|
|
Loading…
Reference in New Issue