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:
Tim Allen 2015-11-10 22:02:29 +11:00
parent 0fe55e3f5b
commit d1ffd59c29
59 changed files with 853 additions and 746 deletions

View File

@ -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

View File

@ -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 {}
}; };

View File

@ -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;
}; };

View File

@ -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>

View File

@ -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);
} }
} }

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;

View File

@ -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 {
} }

View File

@ -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);
} }

View File

@ -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 {

View File

@ -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>

View File

@ -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;

View File

@ -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

View File

@ -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/)

View File

@ -1 +0,0 @@
#include <sfc/base/satellaview/satellaview.hpp>

View File

@ -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++) {

View File

@ -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();
} }

View File

@ -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 {

View File

@ -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);
} }
} }

View File

@ -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;

View File

@ -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++) {

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -1,3 +1,5 @@
//Sony CXD1222Q-1
struct DSP : Thread { struct DSP : Thread {
enum : bool { Threaded = true }; enum : bool { Threaded = true };

View File

@ -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 {
}
}

View File

@ -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;

View File

@ -0,0 +1,2 @@
#include <sfc/expansion/eboot/eboot.hpp>
#include <sfc/expansion/satellaview/satellaview.hpp>

View File

@ -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;

View File

@ -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();
} }

View File

@ -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,
}; };
}; };

View File

@ -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));

View File

@ -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>

View File

@ -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];
} }

View File

@ -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);
} }

View File

@ -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() {
}
} }

View File

@ -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;

View File

@ -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

View File

@ -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) {

47
sfc/system/device.cpp Normal file
View File

@ -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

28
sfc/system/device.hpp Normal file
View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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 {

View File

@ -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};