mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-23 17:09:44 +00:00
Update to v095r04 release.
Changelog: - S-SMP core code style updated - S-SMP loads reset vector from IPLROM ($fffe-ffff) - sfc/base => sfc/expansion - system/input => system/device - added expansion/eBoot (simulation of defparam's SNES-Boot device) - expansion port device can now be selected from Super Famicom menu option - improved GBA MROM/SRAM reading endrift's memory test is up to 1388/1552. Note: I added the expansion port devices to the same group as controller ports. I also had to move "None" to the top of the list. Before v096, I am going to have to add caching of port selections to the configuration file, check the proper default item in the system menu, and remove the items with no mappings from the input configuration window. Lots of work >_>
This commit is contained in:
parent
0fe55e3f5b
commit
d1ffd59c29
@ -7,7 +7,7 @@ using namespace nall;
|
||||
|
||||
namespace Emulator {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
@ -54,75 +54,6 @@ template<typename R, typename... P> struct hook<R (P...)> {
|
||||
#define privileged private
|
||||
#endif
|
||||
|
||||
typedef int1_t int1;
|
||||
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;
|
||||
using varuint = varuint_t<uint>;
|
||||
|
||||
#endif
|
||||
|
@ -6,8 +6,8 @@ namespace Emulator {
|
||||
struct Interface {
|
||||
struct Information {
|
||||
string name;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
uint width;
|
||||
uint height;
|
||||
bool overscan;
|
||||
double aspectRatio;
|
||||
bool resettable;
|
||||
@ -18,7 +18,7 @@ struct Interface {
|
||||
} information;
|
||||
|
||||
struct Media {
|
||||
unsigned id;
|
||||
uint id;
|
||||
string name;
|
||||
string type;
|
||||
bool bootable; //false for cartridge slots (eg Sufami Turbo cartridges)
|
||||
@ -26,52 +26,52 @@ struct Interface {
|
||||
vector<Media> media;
|
||||
|
||||
struct Device {
|
||||
unsigned id;
|
||||
unsigned portmask;
|
||||
uint id;
|
||||
uint portmask;
|
||||
string name;
|
||||
struct Input {
|
||||
unsigned id;
|
||||
unsigned type; //0 = digital, 1 = analog (relative), 2 = rumble
|
||||
uint id;
|
||||
uint type; //0 = digital, 1 = analog (relative), 2 = rumble
|
||||
string name;
|
||||
uintptr_t guid; //user data field
|
||||
};
|
||||
vector<Input> input;
|
||||
vector<unsigned> order;
|
||||
vector<uint> order;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
unsigned id;
|
||||
uint id;
|
||||
string name;
|
||||
vector<Device> device;
|
||||
};
|
||||
vector<Port> port;
|
||||
|
||||
struct Bind {
|
||||
virtual auto loadRequest(unsigned, string, string, bool) -> void {}
|
||||
virtual auto loadRequest(unsigned, string, bool) -> void {}
|
||||
virtual auto saveRequest(unsigned, string) -> void {}
|
||||
virtual auto videoColor(unsigned, uint16_t, uint16_t, uint16_t, uint16_t) -> uint32_t { return 0u; }
|
||||
virtual auto videoRefresh(const uint32_t*, const uint32_t*, unsigned, unsigned, unsigned) -> void {}
|
||||
virtual auto audioSample(int16_t, int16_t) -> void {}
|
||||
virtual auto inputPoll(unsigned, unsigned, unsigned) -> int16_t { return 0; }
|
||||
virtual auto inputRumble(unsigned, unsigned, unsigned, bool) -> void {}
|
||||
virtual auto dipSettings(const Markup::Node&) -> unsigned { return 0; }
|
||||
virtual auto path(unsigned) -> string { return ""; }
|
||||
virtual auto loadRequest(uint, string, string, bool) -> void {}
|
||||
virtual auto loadRequest(uint, string, bool) -> void {}
|
||||
virtual auto saveRequest(uint, string) -> void {}
|
||||
virtual auto videoColor(uint, uint16, uint16, uint16, uint16) -> uint32 { return 0u; }
|
||||
virtual auto videoRefresh(const uint32*, const uint32*, uint, uint, uint) -> void {}
|
||||
virtual auto audioSample(int16, int16) -> void {}
|
||||
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
|
||||
virtual auto inputRumble(uint, uint, uint, bool) -> void {}
|
||||
virtual auto dipSettings(const Markup::Node&) -> uint { return 0; }
|
||||
virtual auto path(uint) -> string { return ""; }
|
||||
virtual auto notify(string text) -> void { print(text, "\n"); }
|
||||
};
|
||||
Bind* bind = nullptr;
|
||||
|
||||
//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(unsigned 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 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 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 audioSample(int16_t lsample, int16_t rsample) -> void { return bind->audioSample(lsample, rsample); }
|
||||
auto inputPoll(unsigned port, unsigned device, unsigned input) -> int16_t { 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 dipSettings(const Markup::Node& node) -> unsigned { return bind->dipSettings(node); }
|
||||
auto path(unsigned group) -> string { return bind->path(group); }
|
||||
auto loadRequest(uint id, string name, string type, bool required) -> void { return bind->loadRequest(id, name, type, required); }
|
||||
auto loadRequest(uint id, string path, bool required) -> void { return bind->loadRequest(id, path, required); }
|
||||
auto saveRequest(uint id, string path) -> void { return bind->saveRequest(id, path); }
|
||||
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* palette, const uint32* data, uint pitch, uint width, uint height) -> void { return bind->videoRefresh(palette, data, pitch, width, height); }
|
||||
auto audioSample(int16 lsample, int16 rsample) -> void { return bind->audioSample(lsample, rsample); }
|
||||
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
|
||||
auto inputRumble(uint port, uint device, uint input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
||||
auto dipSettings(const Markup::Node& node) -> uint { return bind->dipSettings(node); }
|
||||
auto path(uint group) -> string { return bind->path(group); }
|
||||
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
|
||||
|
||||
//information
|
||||
@ -82,15 +82,15 @@ struct Interface {
|
||||
//media interface
|
||||
virtual auto loaded() -> bool { return false; }
|
||||
virtual auto sha256() -> string { return ""; }
|
||||
virtual auto group(unsigned id) -> unsigned = 0;
|
||||
virtual auto load(unsigned id) -> void {}
|
||||
virtual auto group(uint id) -> uint = 0;
|
||||
virtual auto load(uint id) -> void {}
|
||||
virtual auto save() -> void {}
|
||||
virtual auto load(unsigned id, const stream& memory) -> void {}
|
||||
virtual auto save(unsigned id, const stream& memory) -> void {}
|
||||
virtual auto load(uint id, const stream& memory) -> void {}
|
||||
virtual auto save(uint id, const stream& memory) -> void {}
|
||||
virtual auto unload() -> void {}
|
||||
|
||||
//system interface
|
||||
virtual auto connect(unsigned port, unsigned device) -> void {}
|
||||
virtual auto connect(uint port, uint device) -> void {}
|
||||
virtual auto power() -> void {}
|
||||
virtual auto reset() -> void {}
|
||||
virtual auto run() -> void {}
|
||||
@ -107,7 +107,7 @@ struct Interface {
|
||||
virtual auto cheatSet(const lstring& = lstring{}) -> void {}
|
||||
|
||||
//utility functions
|
||||
enum class PaletteMode : unsigned { Literal, Channel, Standard, Emulation };
|
||||
enum class PaletteMode : uint { Literal, Channel, Standard, Emulation };
|
||||
virtual auto paletteUpdate(PaletteMode mode) -> void {}
|
||||
};
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace Famicom {
|
||||
namespace Info {
|
||||
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);
|
||||
}
|
||||
|
||||
auto create(void (*entrypoint)(), unsigned frequency) -> void {
|
||||
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||
if(thread) co_delete(thread);
|
||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
@ -39,7 +39,7 @@ namespace Famicom {
|
||||
}
|
||||
|
||||
cothread_t thread = nullptr;
|
||||
unsigned frequency = 0;
|
||||
uint frequency = 0;
|
||||
int64 clock = 0;
|
||||
};
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace GameBoy {
|
||||
namespace Info {
|
||||
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);
|
||||
}
|
||||
|
||||
auto create(void (*entrypoint)(), unsigned frequency) -> void {
|
||||
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||
if(thread) co_delete(thread);
|
||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
@ -39,8 +39,8 @@ namespace GameBoy {
|
||||
}
|
||||
|
||||
cothread_t thread = nullptr;
|
||||
unsigned frequency = 0;
|
||||
int64_t clock = 0;
|
||||
uint frequency = 0;
|
||||
int64 clock = 0;
|
||||
};
|
||||
|
||||
#include <gb/memory/memory.hpp>
|
||||
|
@ -10,7 +10,6 @@ namespace GameBoyAdvance {
|
||||
Cartridge cartridge;
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
mrom.data = new uint8[mrom.size = 32 * 1024 * 1024];
|
||||
sram.data = new uint8[sram.size = 32 * 1024];
|
||||
eeprom.data = new uint8[eeprom.size = 8 * 1024];
|
||||
@ -24,6 +23,14 @@ Cartridge::~Cartridge() {
|
||||
delete[] flash.data;
|
||||
}
|
||||
|
||||
auto Cartridge::loaded() const -> bool {
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
auto Cartridge::sha256() const -> string {
|
||||
return information.sha256;
|
||||
}
|
||||
|
||||
auto Cartridge::title() const -> string {
|
||||
return information.title;
|
||||
}
|
||||
@ -34,21 +41,18 @@ auto Cartridge::load() -> void {
|
||||
auto document = BML::unserialize(information.markup);
|
||||
information.title = document["information/title"].text();
|
||||
|
||||
unsigned mrom_size = 0;
|
||||
hasSRAM = false;
|
||||
hasEEPROM = false;
|
||||
hasFLASH = false;
|
||||
|
||||
if(auto info = document["cartridge/mrom"]) {
|
||||
mrom.size = min(32 * 1024 * 1024, info["size"].decimal());
|
||||
|
||||
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"]) {
|
||||
has_sram = true;
|
||||
hasSRAM = true;
|
||||
sram.size = min(32 * 1024, info["size"].decimal());
|
||||
sram.mask = sram.size - 1;
|
||||
for(auto n : range(sram.size)) sram.data[n] = 0xff;
|
||||
@ -58,12 +62,12 @@ auto Cartridge::load() -> void {
|
||||
}
|
||||
|
||||
if(auto info = document["cartridge/eeprom"]) {
|
||||
has_eeprom = true;
|
||||
hasEEPROM = true;
|
||||
eeprom.size = min(8 * 1024, info["size"].decimal());
|
||||
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
||||
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
||||
eeprom.mask = mrom_size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||
eeprom.test = mrom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||
eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
|
||||
|
||||
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
|
||||
@ -71,7 +75,7 @@ auto Cartridge::load() -> void {
|
||||
}
|
||||
|
||||
if(auto info = document["cartridge/flash"]) {
|
||||
has_flash = true;
|
||||
hasFLASH = true;
|
||||
flash.id = info["id"].decimal();
|
||||
flash.size = min(128 * 1024, info["size"].decimal());
|
||||
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()});
|
||||
}
|
||||
|
||||
sha256 = Hash::SHA256(mrom.data, mrom_size).digest();
|
||||
information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest();
|
||||
|
||||
system.load();
|
||||
loaded = true;
|
||||
isLoaded = true;
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
if(loaded) {
|
||||
loaded = false;
|
||||
if(isLoaded) {
|
||||
isLoaded = false;
|
||||
memory.reset();
|
||||
}
|
||||
}
|
||||
@ -105,24 +109,24 @@ auto Cartridge::power() -> void {
|
||||
|
||||
#define RAM_ANALYZE
|
||||
|
||||
auto Cartridge::read(unsigned mode, uint32 addr) -> uint32 {
|
||||
auto Cartridge::read(uint mode, uint32 addr) -> uint32 {
|
||||
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);
|
||||
} else {
|
||||
if(has_sram) return sram.read(mode, addr);
|
||||
if(has_flash) return flash.read(addr);
|
||||
if(hasSRAM) return sram.read(mode, addr);
|
||||
if(hasFLASH) return flash.read(addr);
|
||||
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(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);
|
||||
} else {
|
||||
if(has_sram) return sram.write(mode, addr, word);
|
||||
if(has_flash) return flash.write(addr, word);
|
||||
if(hasSRAM) return sram.write(mode, addr, word);
|
||||
if(hasFLASH) return flash.write(addr, word);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,18 @@
|
||||
struct Cartridge : property<Cartridge> {
|
||||
struct Cartridge {
|
||||
#include "memory.hpp"
|
||||
|
||||
readonly<bool> loaded;
|
||||
readonly<string> sha256;
|
||||
|
||||
readonly<bool> has_sram;
|
||||
readonly<bool> has_eeprom;
|
||||
readonly<bool> has_flash;
|
||||
auto loaded() const -> bool;
|
||||
auto sha256() const -> string;
|
||||
auto title() const -> string;
|
||||
|
||||
struct Information {
|
||||
string markup;
|
||||
string sha256;
|
||||
string title;
|
||||
} information;
|
||||
|
||||
struct Media {
|
||||
unsigned id;
|
||||
uint id;
|
||||
string name;
|
||||
};
|
||||
vector<Media> memory;
|
||||
@ -22,16 +20,20 @@ struct Cartridge : property<Cartridge> {
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
|
||||
auto title() const -> string;
|
||||
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto read(unsigned mode, uint32 addr) -> uint32;
|
||||
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
||||
auto read(uint mode, uint32 addr) -> uint32;
|
||||
auto write(uint mode, uint32 addr, uint32 word) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
bool isLoaded = false;
|
||||
bool hasSRAM = false;
|
||||
bool hasEEPROM = false;
|
||||
bool hasFLASH = false;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
@ -1,8 +1,8 @@
|
||||
auto Cartridge::EEPROM::read(unsigned addr) -> bool {
|
||||
auto Cartridge::EEPROM::read(uint addr) -> bool {
|
||||
return data[addr >> 3] & 0x80 >> (addr & 7);
|
||||
}
|
||||
|
||||
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 == 1) data[addr >> 3] |= (0x80 >> (addr & 7));
|
||||
}
|
||||
@ -88,7 +88,7 @@ auto Cartridge::EEPROM::serialize(serializer& s) -> void {
|
||||
s.integer(mask);
|
||||
s.integer(test);
|
||||
s.integer(bits);
|
||||
s.integer((unsigned&)mode);
|
||||
s.integer((uint&)mode);
|
||||
s.integer(offset);
|
||||
s.integer(address);
|
||||
}
|
||||
|
@ -1,45 +1,41 @@
|
||||
struct Memory {
|
||||
auto ror(uint32 word, unsigned shift) -> uint32 {
|
||||
return word << 32 - shift | word >> shift;
|
||||
}
|
||||
};
|
||||
|
||||
struct MROM : Memory {
|
||||
struct MROM {
|
||||
uint8* data;
|
||||
unsigned size;
|
||||
unsigned mask;
|
||||
uint size;
|
||||
uint mask;
|
||||
|
||||
auto read(unsigned mode, uint32 addr) -> uint32;
|
||||
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
||||
auto read(uint mode, uint32 addr) -> uint32;
|
||||
auto write(uint mode, uint32 addr, uint32 word) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
} mrom;
|
||||
|
||||
struct SRAM : Memory {
|
||||
struct SRAM {
|
||||
uint8* data;
|
||||
unsigned size;
|
||||
unsigned mask;
|
||||
uint size;
|
||||
uint mask;
|
||||
|
||||
auto read(unsigned mode, uint32 addr) -> uint32;
|
||||
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
||||
auto read(uint mode, uint32 addr) -> uint32;
|
||||
auto write(uint mode, uint32 addr, uint32 word) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
} sram;
|
||||
|
||||
struct EEPROM : Memory {
|
||||
struct EEPROM {
|
||||
uint8* data;
|
||||
unsigned size;
|
||||
unsigned mask;
|
||||
unsigned test;
|
||||
unsigned bits;
|
||||
uint size;
|
||||
uint mask;
|
||||
uint test;
|
||||
uint bits;
|
||||
|
||||
enum class Mode : unsigned {
|
||||
enum class Mode : uint {
|
||||
Wait, Command, ReadAddress, ReadValidate, ReadData, WriteAddress, WriteData, WriteValidate
|
||||
} mode;
|
||||
unsigned offset;
|
||||
unsigned address;
|
||||
unsigned addressbits;
|
||||
uint offset;
|
||||
uint address;
|
||||
uint addressbits;
|
||||
|
||||
auto read(unsigned addr) -> bool;
|
||||
auto write(unsigned addr, bool bit) -> void;
|
||||
auto read(uint addr) -> bool;
|
||||
auto write(uint addr, bool bit) -> void;
|
||||
|
||||
auto read() -> bool;
|
||||
auto write(bool bit) -> void;
|
||||
@ -47,9 +43,9 @@ struct EEPROM : Memory {
|
||||
auto serialize(serializer&) -> void;
|
||||
} eeprom;
|
||||
|
||||
struct FLASH : Memory {
|
||||
struct FLASH {
|
||||
uint8* data;
|
||||
unsigned size;
|
||||
uint size;
|
||||
uint16 id;
|
||||
|
||||
bool unlockhi;
|
||||
|
@ -1,12 +1,23 @@
|
||||
auto Cartridge::MROM::read(unsigned mode, uint32 addr) -> uint32 {
|
||||
if(mode & Word) addr &= ~3;
|
||||
auto Cartridge::MROM::read(uint mode, uint32 addr) -> uint32 {
|
||||
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;
|
||||
auto p = data + (addr & 0x01ff'ffff);
|
||||
if(mode & Word) return p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24;
|
||||
auto p = data + addr;
|
||||
if(mode & Half) return p[0] << 0 | p[1] << 8;
|
||||
if(mode & Byte) return p[0] << 0;
|
||||
return 0; //should never occur
|
||||
}
|
||||
|
||||
auto Cartridge::MROM::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||
auto Cartridge::MROM::write(uint mode, uint32 addr, uint32 word) -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::MROM::serialize(serializer& s) -> void {
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
void Cartridge::serialize(serializer& s) {
|
||||
if(has_sram) sram.serialize(s);
|
||||
if(has_eeprom) eeprom.serialize(s);
|
||||
if(has_flash) flash.serialize(s);
|
||||
mrom.serialize(s);
|
||||
if(hasSRAM) sram.serialize(s);
|
||||
if(hasEEPROM) eeprom.serialize(s);
|
||||
if(hasFLASH) flash.serialize(s);
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
auto Cartridge::SRAM::read(unsigned mode, uint32 addr) -> uint32 {
|
||||
if(mode & Word) addr &= ~3;
|
||||
if(mode & Half) addr &= ~1;
|
||||
auto Cartridge::SRAM::read(uint mode, uint32 addr) -> uint32 {
|
||||
uint32 word = data[addr & mask];
|
||||
word = ror(word, 8 * (addr & 3));
|
||||
if(mode & Word) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||
if(mode & Half) { word &= 0xff; word |= word << 8; }
|
||||
word |= word << 8;
|
||||
word |= word << 16;
|
||||
return word;
|
||||
}
|
||||
|
||||
auto Cartridge::SRAM::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||
data[addr & mask] = ror(word, 8 * (addr & 3));
|
||||
auto Cartridge::SRAM::write(uint mode, uint32 addr, uint32 word) -> void {
|
||||
data[addr & mask] = word;
|
||||
}
|
||||
|
||||
auto Cartridge::SRAM::serialize(serializer& s) -> void {
|
||||
|
11
gba/gba.hpp
11
gba/gba.hpp
@ -7,7 +7,7 @@
|
||||
namespace GameBoyAdvance {
|
||||
namespace Info {
|
||||
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>
|
||||
|
||||
namespace GameBoyAdvance {
|
||||
enum : unsigned { //mode flags for bus_read, bus_write:
|
||||
enum : uint { //mode flags for bus read, write:
|
||||
Nonsequential = 1, //N cycle
|
||||
Sequential = 2, //S cycle
|
||||
Prefetch = 4, //instruction fetch (eligible for prefetch)
|
||||
@ -30,6 +30,7 @@ namespace GameBoyAdvance {
|
||||
Word = 32, //32-bit access
|
||||
Load = 64, //load operation
|
||||
Store = 128, //store operation
|
||||
Signed = 256, //sign extended
|
||||
};
|
||||
|
||||
struct Thread {
|
||||
@ -37,7 +38,7 @@ namespace GameBoyAdvance {
|
||||
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);
|
||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
@ -50,8 +51,8 @@ namespace GameBoyAdvance {
|
||||
}
|
||||
|
||||
cothread_t thread = nullptr;
|
||||
unsigned frequency = 0;
|
||||
signed clock = 0;
|
||||
uint frequency = 0;
|
||||
int clock = 0;
|
||||
};
|
||||
|
||||
#include <gba/memory/memory.hpp>
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef NALL_STDINT_HPP
|
||||
#define NALL_STDINT_HPP
|
||||
|
||||
using uint = unsigned int;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
|
200
nall/varint.hpp
200
nall/varint.hpp
@ -145,75 +145,139 @@ private:
|
||||
|
||||
}
|
||||
|
||||
//typedefs
|
||||
typedef nall::uint_t< 1> uint1_t;
|
||||
typedef nall::uint_t< 2> uint2_t;
|
||||
typedef nall::uint_t< 3> uint3_t;
|
||||
typedef nall::uint_t< 4> uint4_t;
|
||||
typedef nall::uint_t< 5> uint5_t;
|
||||
typedef nall::uint_t< 6> uint6_t;
|
||||
typedef nall::uint_t< 7> uint7_t;
|
||||
//typedef nall::uint_t< 8> uint8_t;
|
||||
using int1 = nall::int_t<1>;
|
||||
using int2 = nall::int_t<2>;
|
||||
using int3 = nall::int_t<3>;
|
||||
using int4 = nall::int_t<4>;
|
||||
using int5 = nall::int_t<5>;
|
||||
using int6 = nall::int_t<6>;
|
||||
using int7 = nall::int_t<7>;
|
||||
using int8 = int8_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;
|
||||
typedef nall::uint_t<10> uint10_t;
|
||||
typedef nall::uint_t<11> uint11_t;
|
||||
typedef nall::uint_t<12> uint12_t;
|
||||
typedef nall::uint_t<13> uint13_t;
|
||||
typedef nall::uint_t<14> uint14_t;
|
||||
typedef nall::uint_t<15> uint15_t;
|
||||
//typedef nall::uint_t<16> uint16_t;
|
||||
using uint1 = nall::uint_t<1>;
|
||||
using uint2 = nall::uint_t<2>;
|
||||
using uint3 = nall::uint_t<3>;
|
||||
using uint4 = nall::uint_t<4>;
|
||||
using uint5 = nall::uint_t<5>;
|
||||
using uint6 = nall::uint_t<6>;
|
||||
using uint7 = nall::uint_t<7>;
|
||||
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;
|
||||
typedef nall::uint_t<18> uint18_t;
|
||||
typedef nall::uint_t<19> uint19_t;
|
||||
typedef nall::uint_t<20> uint20_t;
|
||||
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;
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
using int128 = int128_t;
|
||||
using uint128 = uint128_t;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
sfc_objects := sfc-interface sfc-system sfc-controller
|
||||
sfc_objects += sfc-cartridge sfc-cheat
|
||||
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-sa1 sfc-superfx
|
||||
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-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-mcc.o: $(sfc)/chip/mcc/mcc.cpp $(call rwildcard,$(sfc)/chip/mcc/)
|
||||
|
@ -1 +0,0 @@
|
||||
#include <sfc/base/satellaview/satellaview.hpp>
|
@ -134,7 +134,7 @@ void SA1::power() {
|
||||
}
|
||||
|
||||
void SA1::reset() {
|
||||
create(SA1::Enter, system.cpu_frequency());
|
||||
create(SA1::Enter, system.cpuFrequency());
|
||||
|
||||
cpubwram.dma = false;
|
||||
for(unsigned addr = 0; addr < iram.size(); addr++) {
|
||||
|
@ -54,7 +54,7 @@ auto SuperFX::power() -> void {
|
||||
|
||||
auto SuperFX::reset() -> void {
|
||||
GSU::reset();
|
||||
create(SuperFX::Enter, system.cpu_frequency());
|
||||
create(SuperFX::Enter, system.cpuFrequency());
|
||||
memory_reset();
|
||||
timing_reset();
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ Controller::Controller(bool port) : port(port) {
|
||||
}
|
||||
|
||||
auto Controller::Enter() -> void {
|
||||
if(co_active() == input.port1->thread) input.port1->enter();
|
||||
if(co_active() == input.port2->thread) input.port2->enter();
|
||||
if(co_active() == device.controllerPort1->thread) device.controllerPort1->enter();
|
||||
if(co_active() == device.controllerPort2->thread) device.controllerPort2->enter();
|
||||
}
|
||||
|
||||
auto Controller::enter() -> void {
|
||||
|
@ -11,7 +11,7 @@ Gamepad::Gamepad(bool port) : Controller(port) {
|
||||
|
||||
auto Gamepad::data() -> uint2 {
|
||||
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
|
||||
switch(counter++) {
|
||||
@ -38,19 +38,19 @@ auto Gamepad::latch(bool data) -> void {
|
||||
counter = 0;
|
||||
|
||||
if(latched == 0) {
|
||||
unsigned id = (unsigned)Input::Device::Joypad;
|
||||
b = interface->inputPoll(port, id, 0);
|
||||
y = interface->inputPoll(port, id, 1);
|
||||
select = interface->inputPoll(port, id, 2);
|
||||
start = interface->inputPoll(port, id, 3);
|
||||
up = interface->inputPoll(port, id, 4);
|
||||
down = interface->inputPoll(port, id, 5);
|
||||
left = interface->inputPoll(port, id, 6);
|
||||
right = interface->inputPoll(port, id, 7);
|
||||
a = interface->inputPoll(port, id, 8);
|
||||
x = interface->inputPoll(port, id, 9);
|
||||
l = interface->inputPoll(port, id, 10);
|
||||
r = interface->inputPoll(port, id, 11);
|
||||
auto id = (unsigned)Device::ID::Gamepad;
|
||||
b = interface->inputPoll(port, id, B);
|
||||
y = interface->inputPoll(port, id, Y);
|
||||
select = interface->inputPoll(port, id, Select);
|
||||
start = interface->inputPoll(port, id, Start);
|
||||
up = interface->inputPoll(port, id, Up);
|
||||
down = interface->inputPoll(port, id, Down);
|
||||
left = interface->inputPoll(port, id, Left);
|
||||
right = interface->inputPoll(port, id, Right);
|
||||
a = interface->inputPoll(port, id, A);
|
||||
x = interface->inputPoll(port, id, X);
|
||||
l = interface->inputPoll(port, id, L);
|
||||
r = interface->inputPoll(port, id, R);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,8 @@
|
||||
struct Gamepad : Controller {
|
||||
enum : uint {
|
||||
B, Y, Select, Start, Up, Down, Left, Right, A, X, L, R,
|
||||
};
|
||||
|
||||
Gamepad(bool port);
|
||||
|
||||
auto data() -> uint2;
|
||||
|
@ -3,7 +3,7 @@
|
||||
Justifier::Justifier(bool port, bool chained):
|
||||
Controller(port),
|
||||
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);
|
||||
latched = 0;
|
||||
@ -47,8 +47,8 @@ auto Justifier::enter() -> void {
|
||||
}
|
||||
|
||||
if(next < prev) {
|
||||
int nx1 = interface->inputPoll(port, device, 0 + (unsigned)Input::JustifierID::X);
|
||||
int ny1 = interface->inputPoll(port, device, 0 + (unsigned)Input::JustifierID::Y);
|
||||
int nx1 = interface->inputPoll(port, device, 0 + X);
|
||||
int ny1 = interface->inputPoll(port, device, 0 + Y);
|
||||
nx1 += player1.x;
|
||||
ny1 += player1.y;
|
||||
player1.x = max(-16, min(256 + 16, nx1));
|
||||
@ -56,8 +56,8 @@ auto Justifier::enter() -> void {
|
||||
}
|
||||
|
||||
if(next < prev && chained) {
|
||||
int nx2 = interface->inputPoll(port, device, 4 + (unsigned)Input::JustifierID::X);
|
||||
int ny2 = interface->inputPoll(port, device, 4 + (unsigned)Input::JustifierID::Y);
|
||||
int nx2 = interface->inputPoll(port, device, 4 + X);
|
||||
int ny2 = interface->inputPoll(port, device, 4 + Y);
|
||||
nx2 += player2.x;
|
||||
ny2 += player2.y;
|
||||
player2.x = max(-16, min(256 + 16, nx2));
|
||||
@ -73,13 +73,13 @@ auto Justifier::data() -> uint2 {
|
||||
if(counter >= 32) return 1;
|
||||
|
||||
if(counter == 0) {
|
||||
player1.trigger = interface->inputPoll(port, device, 0 + (unsigned)Input::JustifierID::Trigger);
|
||||
player1.start = interface->inputPoll(port, device, 0 + (unsigned)Input::JustifierID::Start);
|
||||
player1.trigger = interface->inputPoll(port, device, 0 + Trigger);
|
||||
player1.start = interface->inputPoll(port, device, 0 + Start);
|
||||
}
|
||||
|
||||
if(counter == 0 && chained) {
|
||||
player2.trigger = interface->inputPoll(port, device, 4 + (unsigned)Input::JustifierID::Trigger);
|
||||
player2.start = interface->inputPoll(port, device, 4 + (unsigned)Input::JustifierID::Start);
|
||||
player2.trigger = interface->inputPoll(port, device, 4 + Trigger);
|
||||
player2.start = interface->inputPoll(port, device, 4 + Start);
|
||||
}
|
||||
|
||||
switch(counter++) {
|
||||
|
@ -1,4 +1,8 @@
|
||||
struct Justifier : Controller {
|
||||
enum : uint {
|
||||
X, Y, Trigger, Start,
|
||||
};
|
||||
|
||||
Justifier(bool port, bool chained);
|
||||
|
||||
auto enter() -> void;
|
||||
|
@ -66,10 +66,10 @@ auto Mouse::latch(bool data) -> void {
|
||||
latched = data;
|
||||
counter = 0;
|
||||
|
||||
x = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::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
|
||||
l = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Left );
|
||||
r = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Right);
|
||||
x = interface->inputPoll(port, (unsigned)Device::ID::Mouse, X); //-n = left, 0 = center, +n = right
|
||||
y = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Y); //-n = up, 0 = center, +n = down
|
||||
l = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Left);
|
||||
r = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Right);
|
||||
|
||||
dx = x < 0; //0 = right, 1 = left
|
||||
dy = y < 0; //0 = down, 1 = up
|
||||
|
@ -1,4 +1,8 @@
|
||||
struct Mouse : Controller {
|
||||
enum : uint {
|
||||
X, Y, Left, Right,
|
||||
};
|
||||
|
||||
Mouse(bool port);
|
||||
|
||||
auto data() -> uint2;
|
||||
|
@ -26,8 +26,8 @@ auto Multitap::data() -> uint2 {
|
||||
port2 = 3; //controller 4
|
||||
}
|
||||
|
||||
bool data1 = interface->inputPoll(port, (unsigned)Input::Device::Multitap, port1 * 12 + index);
|
||||
bool data2 = interface->inputPoll(port, (unsigned)Input::Device::Multitap, port2 * 12 + index);
|
||||
bool data1 = interface->inputPoll(port, (unsigned)Device::ID::Multitap, port1 * 12 + index);
|
||||
bool data2 = interface->inputPoll(port, (unsigned)Device::ID::Multitap, port2 * 12 + index);
|
||||
return (data2 << 1) | (data1 << 0);
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,8 @@ auto SuperScope::enter() -> void {
|
||||
|
||||
if(next < prev) {
|
||||
//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 ny = interface->inputPoll(port, (unsigned)Input::Device::SuperScope, (unsigned)Input::SuperScopeID::Y);
|
||||
int nx = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, X);
|
||||
int ny = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Y);
|
||||
nx += x;
|
||||
ny += y;
|
||||
x = max(-16, min(256 + 16, nx));
|
||||
@ -67,7 +67,7 @@ auto SuperScope::data() -> uint2 {
|
||||
|
||||
if(counter == 0) {
|
||||
//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) {
|
||||
turbo = !turbo; //toggle state
|
||||
turbolock = true;
|
||||
@ -78,7 +78,7 @@ auto SuperScope::data() -> uint2 {
|
||||
//trigger is a button
|
||||
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
||||
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)) {
|
||||
trigger = true;
|
||||
triggerlock = true;
|
||||
@ -87,11 +87,11 @@ auto SuperScope::data() -> uint2 {
|
||||
}
|
||||
|
||||
//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 = 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) {
|
||||
pause = true;
|
||||
pauselock = true;
|
||||
|
@ -1,4 +1,8 @@
|
||||
struct SuperScope : Controller {
|
||||
enum : uint {
|
||||
X, Y, Trigger, Cursor, Turbo, Pause,
|
||||
};
|
||||
|
||||
SuperScope(bool port);
|
||||
|
||||
auto enter() -> void;
|
||||
|
@ -26,7 +26,7 @@ USART::USART(bool port) : Controller(port) {
|
||||
txlength = 0;
|
||||
txdata = 0;
|
||||
|
||||
string filename = {interface->path(ID::SuperFamicom), "usart.so"};
|
||||
string filename{interface->path(ID::SuperFamicom), "usart.so"};
|
||||
if(openAbsolute(filename)) {
|
||||
init = sym("usart_init");
|
||||
main = sym("usart_main");
|
||||
@ -93,7 +93,7 @@ auto USART::data() -> uint2 {
|
||||
if(iobit()) {
|
||||
if(counter >= 16) return 1;
|
||||
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++;
|
||||
return result;
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ void CPU::step(unsigned clocks) {
|
||||
auto& chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
input.port1->clock -= clocks * (uint64)input.port1->frequency;
|
||||
input.port2->clock -= clocks * (uint64)input.port2->frequency;
|
||||
device.controllerPort1->clock -= clocks * (uint64)device.controllerPort1->frequency;
|
||||
device.controllerPort2->clock -= clocks * (uint64)device.controllerPort2->frequency;
|
||||
synchronize_controllers();
|
||||
}
|
||||
|
||||
@ -47,8 +47,8 @@ void CPU::synchronize_coprocessors() {
|
||||
}
|
||||
|
||||
void CPU::synchronize_controllers() {
|
||||
if(input.port1->clock < 0) co_switch(input.port1->thread);
|
||||
if(input.port2->clock < 0) co_switch(input.port2->thread);
|
||||
if(device.controllerPort1->clock < 0) co_switch(device.controllerPort1->thread);
|
||||
if(device.controllerPort2->clock < 0) co_switch(device.controllerPort2->thread);
|
||||
}
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
@ -125,7 +125,7 @@ void CPU::power() {
|
||||
}
|
||||
|
||||
void CPU::reset() {
|
||||
create(Enter, system.cpu_frequency());
|
||||
create(Enter, system.cpuFrequency());
|
||||
coprocessors.reset();
|
||||
PPUcounter::reset();
|
||||
|
||||
|
@ -33,8 +33,8 @@ void CPU::mmio_w2183(uint8 data) {
|
||||
//strobing $4016.d0 affects both controller port latches.
|
||||
//$4017 bit 0 writes are ignored.
|
||||
void CPU::mmio_w4016(uint8 data) {
|
||||
input.port1->latch(data & 1);
|
||||
input.port2->latch(data & 1);
|
||||
device.controllerPort1->latch(data & 1);
|
||||
device.controllerPort2->latch(data & 1);
|
||||
}
|
||||
|
||||
//JOYSER0
|
||||
@ -42,7 +42,7 @@ void CPU::mmio_w4016(uint8 data) {
|
||||
//1-0 = Joypad serial data
|
||||
uint8 CPU::mmio_r4016() {
|
||||
uint8 r = regs.mdr & 0xfc;
|
||||
r |= input.port1->data();
|
||||
r |= device.controllerPort1->data();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ uint8 CPU::mmio_r4016() {
|
||||
//1-0 = Joypad serial data
|
||||
uint8 CPU::mmio_r4017() {
|
||||
uint8 r = (regs.mdr & 0xe0) | 0x1c;
|
||||
r |= input.port2->data();
|
||||
r |= device.controllerPort2->data();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -408,7 +408,7 @@ uint8 CPU::mmio_read(unsigned addr) {
|
||||
//APU
|
||||
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
|
||||
synchronize_smp();
|
||||
return smp.port_read(addr);
|
||||
return smp.portRead(addr);
|
||||
}
|
||||
|
||||
//DMA
|
||||
|
@ -9,14 +9,14 @@ void CPU::step_auto_joypad_poll() {
|
||||
|
||||
if(status.auto_joypad_active && status.auto_joypad_latch) {
|
||||
if(status.auto_joypad_counter == 0) {
|
||||
input.port1->latch(1);
|
||||
input.port2->latch(1);
|
||||
input.port1->latch(0);
|
||||
input.port2->latch(0);
|
||||
device.controllerPort1->latch(1);
|
||||
device.controllerPort2->latch(1);
|
||||
device.controllerPort1->latch(0);
|
||||
device.controllerPort2->latch(0);
|
||||
}
|
||||
|
||||
uint2 port0 = input.port1->data();
|
||||
uint2 port1 = input.port2->data();
|
||||
uint2 port0 = device.controllerPort1->data();
|
||||
uint2 port1 = device.controllerPort2->data();
|
||||
|
||||
status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
|
||||
status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
|
||||
|
@ -287,7 +287,7 @@ auto DSP::power() -> void {
|
||||
}
|
||||
|
||||
auto DSP::reset() -> void {
|
||||
create(Enter, system.apu_frequency());
|
||||
create(Enter, system.apuFrequency());
|
||||
|
||||
REG(FLG) = 0xe0;
|
||||
state.noise = 0x4000;
|
||||
|
@ -1,3 +1,5 @@
|
||||
//Sony CXD1222Q-1
|
||||
|
||||
struct DSP : Thread {
|
||||
enum : bool { Threaded = true };
|
||||
|
||||
|
50
sfc/expansion/eboot/eboot.cpp
Normal file
50
sfc/expansion/eboot/eboot.cpp
Normal 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 {
|
||||
}
|
||||
|
||||
}
|
17
sfc/expansion/eboot/eboot.hpp
Normal file
17
sfc/expansion/eboot/eboot.hpp
Normal 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;
|
2
sfc/expansion/expansion.hpp
Normal file
2
sfc/expansion/expansion.hpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include <sfc/expansion/eboot/eboot.hpp>
|
||||
#include <sfc/expansion/satellaview/satellaview.hpp>
|
@ -1,6 +1,6 @@
|
||||
#include <sfc/sfc.hpp>
|
||||
|
||||
#define SATELLAVIEW_BASE_UNIT_CPP
|
||||
#define SATELLAVIEW_EXPANSION_CPP
|
||||
namespace SuperFamicom {
|
||||
|
||||
SatellaviewBaseUnit satellaviewbaseunit;
|
@ -22,7 +22,11 @@ Interface::Interface() {
|
||||
media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", 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({ 1, 0, "Y" });
|
||||
device.input.append({ 2, 0, "Select"});
|
||||
@ -39,7 +43,7 @@ Interface::Interface() {
|
||||
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) {
|
||||
device.input.append({n + 0, 0, {"Port ", p, " - ", "B" }});
|
||||
device.input.append({n + 1, 0, {"Port ", p, " - ", "Y" }});
|
||||
@ -59,7 +63,7 @@ Interface::Interface() {
|
||||
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({1, 1, "Y-axis"});
|
||||
device.input.append({2, 0, "Left" });
|
||||
@ -68,7 +72,7 @@ Interface::Interface() {
|
||||
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({1, 1, "Y-axis" });
|
||||
device.input.append({2, 0, "Trigger"});
|
||||
@ -79,7 +83,7 @@ Interface::Interface() {
|
||||
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({1, 1, "Y-axis" });
|
||||
device.input.append({2, 0, "Trigger"});
|
||||
@ -88,7 +92,7 @@ Interface::Interface() {
|
||||
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({1, 1, "Port 1 - Y-axis" });
|
||||
device.input.append({2, 0, "Port 1 - Trigger"});
|
||||
@ -102,16 +106,21 @@ Interface::Interface() {
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{6, ID::Port1, "Serial USART"};
|
||||
{ Device device{7, ID::ControllerPort1, "Serial USART"};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{7, ID::Port1 | ID::Port2, "None"};
|
||||
{ Device device{8, ID::ExpansionPort, "Satellaview"};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
port.append({0, "Port 1"});
|
||||
port.append({1, "Port 2"});
|
||||
{ Device device{9, ID::ExpansionPort, "eBoot"};
|
||||
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& port : this->port) {
|
||||
@ -128,13 +137,13 @@ auto Interface::title() -> string {
|
||||
|
||||
auto Interface::videoFrequency() -> double {
|
||||
switch(system.region()) { default:
|
||||
case System::Region::NTSC: return system.cpu_frequency() / (262.0 * 1364.0 - 4.0);
|
||||
case System::Region::PAL: return system.cpu_frequency() / (312.0 * 1364.0);
|
||||
case System::Region::NTSC: return system.cpuFrequency() / (262.0 * 1364.0 - 4.0);
|
||||
case System::Region::PAL: return system.cpuFrequency() / (312.0 * 1364.0);
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::audioFrequency() -> double {
|
||||
return system.apu_frequency() / 768.0;
|
||||
return system.apuFrequency() / 768.0;
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
@ -396,7 +405,7 @@ auto Interface::unload() -> 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 {
|
||||
@ -423,7 +432,7 @@ auto Interface::rtcsync() -> void {
|
||||
}
|
||||
|
||||
auto Interface::serialize() -> serializer {
|
||||
system.runtosave();
|
||||
system.runToSave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
|
@ -83,9 +83,10 @@ struct ID {
|
||||
SufamiTurboSlotBROM,
|
||||
SufamiTurboSlotBRAM,
|
||||
|
||||
//controller ports
|
||||
Port1 = 1,
|
||||
Port2 = 2,
|
||||
//device ports (bitmask)
|
||||
ControllerPort1 = 1,
|
||||
ControllerPort2 = 2,
|
||||
ExpansionPort = 4,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -93,7 +93,7 @@ void PPU::power() {
|
||||
}
|
||||
|
||||
void PPU::reset() {
|
||||
create(Enter, system.cpu_frequency());
|
||||
create(Enter, system.cpuFrequency());
|
||||
PPUcounter::reset();
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint32));
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace SuperFamicom {
|
||||
namespace Info {
|
||||
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);
|
||||
}
|
||||
|
||||
auto create(auto (*entrypoint)() -> void, unsigned frequency) -> void {
|
||||
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||
if(thread) co_delete(thread);
|
||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
@ -45,7 +45,7 @@ namespace SuperFamicom {
|
||||
}
|
||||
|
||||
cothread_t thread = nullptr;
|
||||
unsigned frequency = 0;
|
||||
uint frequency = 0;
|
||||
int64 clock = 0;
|
||||
};
|
||||
|
||||
@ -62,7 +62,7 @@ namespace SuperFamicom {
|
||||
|
||||
#include <sfc/controller/controller.hpp>
|
||||
#include <sfc/system/system.hpp>
|
||||
#include <sfc/base/base.hpp>
|
||||
#include <sfc/expansion/expansion.hpp>
|
||||
#include <sfc/chip/chip.hpp>
|
||||
#include <sfc/slot/slot.hpp>
|
||||
#include <sfc/cartridge/cartridge.hpp>
|
||||
|
@ -1,26 +1,26 @@
|
||||
#ifdef SMP_CPP
|
||||
|
||||
alwaysinline uint8 SMP::ram_read(uint16 addr) {
|
||||
if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f];
|
||||
if(status.ram_disable) return 0x5a; //0xff on mini-SNES
|
||||
alwaysinline auto SMP::ramRead(uint16 addr) -> uint8 {
|
||||
if(addr >= 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
||||
if(status.ramDisable) return 0x5a; //0xff on mini-SNES
|
||||
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
|
||||
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];
|
||||
}
|
||||
|
||||
void SMP::port_write(uint2 port, uint8 data) {
|
||||
auto SMP::portWrite(uint2 port, uint8 data) -> void {
|
||||
apuram[0xf4 + port] = data;
|
||||
}
|
||||
|
||||
uint8 SMP::op_busread(uint16 addr) {
|
||||
unsigned result;
|
||||
auto SMP::busRead(uint16 addr) -> uint8 {
|
||||
uint result;
|
||||
|
||||
switch(addr) {
|
||||
case 0xf0: //TEST -- write-only register
|
||||
@ -30,17 +30,17 @@ uint8 SMP::op_busread(uint16 addr) {
|
||||
return 0x00;
|
||||
|
||||
case 0xf2: //DSPADDR
|
||||
return status.dsp_addr;
|
||||
return status.dspAddr;
|
||||
|
||||
case 0xf3: //DSPDATA
|
||||
//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 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
return cpu.port_read(addr);
|
||||
|
||||
case 0xf8: //RAM0
|
||||
@ -55,50 +55,50 @@ uint8 SMP::op_busread(uint16 addr) {
|
||||
return 0x00;
|
||||
|
||||
case 0xfd: //T0OUT -- 4-bit counter value
|
||||
result = timer0.stage3_ticks;
|
||||
timer0.stage3_ticks = 0;
|
||||
result = timer0.stage3;
|
||||
timer0.stage3 = 0;
|
||||
return result;
|
||||
|
||||
case 0xfe: //T1OUT -- 4-bit counter value
|
||||
result = timer1.stage3_ticks;
|
||||
timer1.stage3_ticks = 0;
|
||||
result = timer1.stage3;
|
||||
timer1.stage3 = 0;
|
||||
return result;
|
||||
|
||||
case 0xff: //T2OUT -- 4-bit counter value
|
||||
result = timer2.stage3_ticks;
|
||||
timer2.stage3_ticks = 0;
|
||||
result = timer2.stage3;
|
||||
timer2.stage3 = 0;
|
||||
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) {
|
||||
case 0xf0: //TEST
|
||||
if(regs.p.p) break; //writes only valid when P flag is clear
|
||||
|
||||
status.clock_speed = (data >> 6) & 3;
|
||||
status.timer_speed = (data >> 4) & 3;
|
||||
status.timers_enable = data & 0x08;
|
||||
status.ram_disable = data & 0x04;
|
||||
status.ram_writable = data & 0x02;
|
||||
status.timers_disable = data & 0x01;
|
||||
status.clockSpeed = (data >> 6) & 3;
|
||||
status.timerSpeed = (data >> 4) & 3;
|
||||
status.timersEnable = data & 0x08;
|
||||
status.ramDisable = data & 0x04;
|
||||
status.ramWritable = data & 0x02;
|
||||
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();
|
||||
timer1.synchronize_stage1();
|
||||
timer2.synchronize_stage1();
|
||||
timer0.synchronizeStage1();
|
||||
timer1.synchronizeStage1();
|
||||
timer2.synchronizeStage1();
|
||||
break;
|
||||
|
||||
case 0xf1: //CONTROL
|
||||
status.iplrom_enable = data & 0x80;
|
||||
status.iplromEnable = data & 0x80;
|
||||
|
||||
if(data & 0x30) {
|
||||
//one-time clearing of APU port read registers,
|
||||
//emulated by simulating CPU writes of 0x00
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
if(data & 0x20) {
|
||||
cpu.port_write(2, 0x00);
|
||||
cpu.port_write(3, 0x00);
|
||||
@ -110,40 +110,40 @@ void SMP::op_buswrite(uint16 addr, uint8 data) {
|
||||
}
|
||||
|
||||
//0->1 transistion resets timers
|
||||
if(timer2.enable == false && (data & 0x04)) {
|
||||
timer2.stage2_ticks = 0;
|
||||
timer2.stage3_ticks = 0;
|
||||
if(!timer2.enable && (data & 0x04)) {
|
||||
timer2.stage2 = 0;
|
||||
timer2.stage3 = 0;
|
||||
}
|
||||
timer2.enable = data & 0x04;
|
||||
|
||||
if(timer1.enable == false && (data & 0x02)) {
|
||||
timer1.stage2_ticks = 0;
|
||||
timer1.stage3_ticks = 0;
|
||||
if(!timer1.enable && (data & 0x02)) {
|
||||
timer1.stage2 = 0;
|
||||
timer1.stage3 = 0;
|
||||
}
|
||||
timer1.enable = data & 0x02;
|
||||
|
||||
if(timer0.enable == false && (data & 0x01)) {
|
||||
timer0.stage2_ticks = 0;
|
||||
timer0.stage3_ticks = 0;
|
||||
if(!timer0.enable && (data & 0x01)) {
|
||||
timer0.stage2 = 0;
|
||||
timer0.stage3 = 0;
|
||||
}
|
||||
timer0.enable = data & 0x01;
|
||||
break;
|
||||
|
||||
case 0xf2: //DSPADDR
|
||||
status.dsp_addr = data;
|
||||
status.dspAddr = data;
|
||||
break;
|
||||
|
||||
case 0xf3: //DSPDATA
|
||||
if(status.dsp_addr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||
dsp.write(status.dsp_addr & 0x7f, data);
|
||||
if(status.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||
dsp.write(status.dspAddr & 0x7f, data);
|
||||
break;
|
||||
|
||||
case 0xf4: //CPUIO0
|
||||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
synchronize_cpu();
|
||||
port_write(addr, data);
|
||||
synchronizeCPU();
|
||||
portWrite(addr, data);
|
||||
break;
|
||||
|
||||
case 0xf8: //RAM0
|
||||
@ -172,33 +172,33 @@ void SMP::op_buswrite(uint16 addr, uint8 data) {
|
||||
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() {
|
||||
add_clocks(24);
|
||||
cycle_edge();
|
||||
auto SMP::op_io() -> void {
|
||||
addClocks(24);
|
||||
cycleEdge();
|
||||
}
|
||||
|
||||
uint8 SMP::op_read(uint16 addr) {
|
||||
add_clocks(12);
|
||||
uint8 data = op_busread(addr);
|
||||
add_clocks(12);
|
||||
cycle_edge();
|
||||
auto SMP::op_read(uint16 addr) -> uint8 {
|
||||
addClocks(12);
|
||||
uint8 data = busRead(addr);
|
||||
addClocks(12);
|
||||
cycleEdge();
|
||||
debugger.op_read(addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void SMP::op_write(uint16 addr, uint8 data) {
|
||||
add_clocks(24);
|
||||
op_buswrite(addr, data);
|
||||
cycle_edge();
|
||||
auto SMP::op_write(uint16 addr, uint8 data) -> void {
|
||||
addClocks(24);
|
||||
busWrite(addr, data);
|
||||
cycleEdge();
|
||||
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 & 0xffc0) == 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f];
|
||||
if((addr & 0xffc0) == 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
||||
return apuram[addr];
|
||||
}
|
||||
|
||||
|
@ -1,50 +1,50 @@
|
||||
#ifdef SMP_CPP
|
||||
|
||||
void SMP::serialize(serializer& s) {
|
||||
auto SMP::serialize(serializer& s) -> void {
|
||||
SPC700::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(apuram);
|
||||
|
||||
s.integer(status.clock_counter);
|
||||
s.integer(status.dsp_counter);
|
||||
s.integer(status.timer_step);
|
||||
s.integer(status.clockCounter);
|
||||
s.integer(status.dspCounter);
|
||||
s.integer(status.timerStep);
|
||||
|
||||
s.integer(status.clock_speed);
|
||||
s.integer(status.timer_speed);
|
||||
s.integer(status.timers_enable);
|
||||
s.integer(status.ram_disable);
|
||||
s.integer(status.ram_writable);
|
||||
s.integer(status.timers_disable);
|
||||
s.integer(status.clockSpeed);
|
||||
s.integer(status.timerSpeed);
|
||||
s.integer(status.timersEnable);
|
||||
s.integer(status.ramDisable);
|
||||
s.integer(status.ramWritable);
|
||||
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.ram00f9);
|
||||
|
||||
s.integer(timer0.stage0_ticks);
|
||||
s.integer(timer0.stage1_ticks);
|
||||
s.integer(timer0.stage2_ticks);
|
||||
s.integer(timer0.stage3_ticks);
|
||||
s.integer(timer0.current_line);
|
||||
s.integer(timer0.stage0);
|
||||
s.integer(timer0.stage1);
|
||||
s.integer(timer0.stage2);
|
||||
s.integer(timer0.stage3);
|
||||
s.integer(timer0.line);
|
||||
s.integer(timer0.enable);
|
||||
s.integer(timer0.target);
|
||||
|
||||
s.integer(timer1.stage0_ticks);
|
||||
s.integer(timer1.stage1_ticks);
|
||||
s.integer(timer1.stage2_ticks);
|
||||
s.integer(timer1.stage3_ticks);
|
||||
s.integer(timer1.current_line);
|
||||
s.integer(timer1.stage0);
|
||||
s.integer(timer1.stage1);
|
||||
s.integer(timer1.stage2);
|
||||
s.integer(timer1.stage3);
|
||||
s.integer(timer1.line);
|
||||
s.integer(timer1.enable);
|
||||
s.integer(timer1.target);
|
||||
|
||||
s.integer(timer2.stage0_ticks);
|
||||
s.integer(timer2.stage1_ticks);
|
||||
s.integer(timer2.stage2_ticks);
|
||||
s.integer(timer2.stage3_ticks);
|
||||
s.integer(timer2.current_line);
|
||||
s.integer(timer2.stage0);
|
||||
s.integer(timer2.stage1);
|
||||
s.integer(timer2.stage2);
|
||||
s.integer(timer2.stage3);
|
||||
s.integer(timer2.line);
|
||||
s.integer(timer2.enable);
|
||||
s.integer(timer2.target);
|
||||
}
|
||||
|
@ -9,30 +9,30 @@ SMP smp;
|
||||
#include "timing.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void SMP::step(unsigned clocks) {
|
||||
auto SMP::step(uint clocks) -> void {
|
||||
clock += clocks * (uint64)cpu.frequency;
|
||||
dsp.clock -= clocks;
|
||||
}
|
||||
|
||||
void SMP::synchronize_cpu() {
|
||||
if(CPU::Threaded == true) {
|
||||
auto SMP::synchronizeCPU() -> void {
|
||||
if(CPU::Threaded) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
}
|
||||
|
||||
void SMP::synchronize_dsp() {
|
||||
if(DSP::Threaded == true) {
|
||||
auto SMP::synchronizeDSP() -> void {
|
||||
if(DSP::Threaded) {
|
||||
if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread);
|
||||
} else {
|
||||
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) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
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
|
||||
timer0.target = 0;
|
||||
timer1.target = 0;
|
||||
timer2.target = 0;
|
||||
}
|
||||
|
||||
void SMP::reset() {
|
||||
create(Enter, system.apu_frequency());
|
||||
auto SMP::reset() -> void {
|
||||
create(Enter, system.apuFrequency());
|
||||
|
||||
regs.pc = 0xffc0;
|
||||
regs.pc.l = iplrom[62];
|
||||
regs.pc.h = iplrom[63];
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.s = 0xef;
|
||||
regs.p = 0x02;
|
||||
|
||||
for(auto& n : apuram) n = random(0x00);
|
||||
for(auto& byte : apuram) byte = random(0x00);
|
||||
apuram[0x00f4] = 0x00;
|
||||
apuram[0x00f5] = 0x00;
|
||||
apuram[0x00f6] = 0x00;
|
||||
apuram[0x00f7] = 0x00;
|
||||
|
||||
status.clock_counter = 0;
|
||||
status.dsp_counter = 0;
|
||||
status.timer_step = 3;
|
||||
status.clockCounter = 0;
|
||||
status.dspCounter = 0;
|
||||
status.timerStep = 3;
|
||||
|
||||
//$00f0
|
||||
status.clock_speed = 0;
|
||||
status.timer_speed = 0;
|
||||
status.timers_enable = true;
|
||||
status.ram_disable = false;
|
||||
status.ram_writable = true;
|
||||
status.timers_disable = false;
|
||||
status.clockSpeed = 0;
|
||||
status.timerSpeed = 0;
|
||||
status.timersEnable = true;
|
||||
status.ramDisable = false;
|
||||
status.ramWritable = true;
|
||||
status.timersDisable = false;
|
||||
|
||||
//$00f1
|
||||
status.iplrom_enable = true;
|
||||
status.iplromEnable = true;
|
||||
|
||||
//$00f2
|
||||
status.dsp_addr = 0x00;
|
||||
status.dspAddr = 0x00;
|
||||
|
||||
//$00f8,$00f9
|
||||
status.ram00f8 = 0x00;
|
||||
status.ram00f9 = 0x00;
|
||||
|
||||
timer0.stage0_ticks = 0;
|
||||
timer1.stage0_ticks = 0;
|
||||
timer2.stage0_ticks = 0;
|
||||
timer0.stage0 = 0;
|
||||
timer1.stage0 = 0;
|
||||
timer2.stage0 = 0;
|
||||
|
||||
timer0.stage1_ticks = 0;
|
||||
timer1.stage1_ticks = 0;
|
||||
timer2.stage1_ticks = 0;
|
||||
timer0.stage1 = 0;
|
||||
timer1.stage1 = 0;
|
||||
timer2.stage1 = 0;
|
||||
|
||||
timer0.stage2_ticks = 0;
|
||||
timer1.stage2_ticks = 0;
|
||||
timer2.stage2_ticks = 0;
|
||||
timer0.stage2 = 0;
|
||||
timer1.stage2 = 0;
|
||||
timer2.stage2 = 0;
|
||||
|
||||
timer0.stage3_ticks = 0;
|
||||
timer1.stage3_ticks = 0;
|
||||
timer2.stage3_ticks = 0;
|
||||
timer0.stage3 = 0;
|
||||
timer1.stage3 = 0;
|
||||
timer2.stage3 = 0;
|
||||
|
||||
timer0.current_line = 0;
|
||||
timer1.current_line = 0;
|
||||
timer2.current_line = 0;
|
||||
timer0.line = 0;
|
||||
timer1.line = 0;
|
||||
timer2.line = 0;
|
||||
|
||||
timer0.enable = false;
|
||||
timer1.enable = false;
|
||||
timer2.enable = false;
|
||||
}
|
||||
|
||||
SMP::SMP() {
|
||||
for(auto& byte : iplrom) byte = 0;
|
||||
}
|
||||
|
||||
SMP::~SMP() {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,52 +1,51 @@
|
||||
//Sony CXP1100Q-1
|
||||
|
||||
struct SMP : Processor::SPC700, Thread {
|
||||
uint8 iplrom[64];
|
||||
uint8 apuram[64 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
alwaysinline void synchronize_dsp();
|
||||
|
||||
uint8 port_read(uint2 port) const;
|
||||
void port_write(uint2 port, uint8 data);
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
alwaysinline auto synchronizeDSP() -> void;
|
||||
|
||||
void enter();
|
||||
void power();
|
||||
void reset();
|
||||
auto portRead(uint2 port) const -> uint8;
|
||||
auto portWrite(uint2 port, uint8 data) -> void;
|
||||
|
||||
void serialize(serializer&);
|
||||
SMP();
|
||||
~SMP();
|
||||
auto enter() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 iplrom[64] = {0};
|
||||
uint8 apuram[64 * 1024] = {0};
|
||||
|
||||
privileged:
|
||||
struct {
|
||||
//timing
|
||||
unsigned clock_counter;
|
||||
unsigned dsp_counter;
|
||||
unsigned timer_step;
|
||||
uint clockCounter;
|
||||
uint dspCounter;
|
||||
uint timerStep;
|
||||
|
||||
//$00f0
|
||||
uint8 clock_speed;
|
||||
uint8 timer_speed;
|
||||
bool timers_enable;
|
||||
bool ram_disable;
|
||||
bool ram_writable;
|
||||
bool timers_disable;
|
||||
uint8 clockSpeed;
|
||||
uint8 timerSpeed;
|
||||
bool timersEnable;
|
||||
bool ramDisable;
|
||||
bool ramWritable;
|
||||
bool timersDisable;
|
||||
|
||||
//$00f1
|
||||
bool iplrom_enable;
|
||||
bool iplromEnable;
|
||||
|
||||
//$00f2
|
||||
uint8 dsp_addr;
|
||||
uint8 dspAddr;
|
||||
|
||||
//$00f8,$00f9
|
||||
uint8 ram00f8;
|
||||
uint8 ram00f9;
|
||||
} status;
|
||||
|
||||
static void Enter();
|
||||
|
||||
friend class SMPcore;
|
||||
static auto Enter() -> void;
|
||||
|
||||
struct Debugger {
|
||||
hook<void (uint16)> op_exec;
|
||||
@ -55,39 +54,39 @@ privileged:
|
||||
} debugger;
|
||||
|
||||
//memory.cpp
|
||||
uint8 ram_read(uint16 addr);
|
||||
void ram_write(uint16 addr, uint8 data);
|
||||
auto ramRead(uint16 addr) -> uint8;
|
||||
auto ramWrite(uint16 addr, uint8 data) -> void;
|
||||
|
||||
uint8 op_busread(uint16 addr);
|
||||
void op_buswrite(uint16 addr, uint8 data);
|
||||
auto busRead(uint16 addr) -> uint8;
|
||||
auto busWrite(uint16 addr, uint8 data) -> void;
|
||||
|
||||
void op_io();
|
||||
uint8 op_read(uint16 addr);
|
||||
void op_write(uint16 addr, uint8 data);
|
||||
auto op_io() -> void;
|
||||
auto op_read(uint16 addr) -> uint8;
|
||||
auto op_write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
uint8 disassembler_read(uint16 addr);
|
||||
auto disassembler_read(uint16 addr) -> uint8;
|
||||
|
||||
//timing.cpp
|
||||
template<unsigned frequency>
|
||||
template<unsigned Frequency>
|
||||
struct Timer {
|
||||
uint8 stage0_ticks;
|
||||
uint8 stage1_ticks;
|
||||
uint8 stage2_ticks;
|
||||
uint4 stage3_ticks;
|
||||
bool current_line;
|
||||
uint8 stage0;
|
||||
uint8 stage1;
|
||||
uint8 stage2;
|
||||
uint4 stage3;
|
||||
bool line;
|
||||
bool enable;
|
||||
uint8 target;
|
||||
|
||||
void tick();
|
||||
void synchronize_stage1();
|
||||
auto tick() -> void;
|
||||
auto synchronizeStage1() -> void;
|
||||
};
|
||||
|
||||
Timer<192> timer0;
|
||||
Timer<192> timer1;
|
||||
Timer< 24> timer2;
|
||||
|
||||
alwaysinline void add_clocks(unsigned clocks);
|
||||
alwaysinline void cycle_edge();
|
||||
alwaysinline auto addClocks(uint clocks) -> void;
|
||||
alwaysinline auto cycleEdge() -> void;
|
||||
};
|
||||
|
||||
extern SMP smp;
|
||||
|
@ -1,62 +1,62 @@
|
||||
#ifdef SMP_CPP
|
||||
|
||||
void SMP::add_clocks(unsigned clocks) {
|
||||
auto SMP::addClocks(uint clocks) -> void {
|
||||
step(clocks);
|
||||
synchronize_dsp();
|
||||
synchronizeDSP();
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
#else
|
||||
//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
|
||||
if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu();
|
||||
if(clock > +(768 * 24 * (int64)24000000)) synchronizeCPU();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SMP::cycle_edge() {
|
||||
auto SMP::cycleEdge() -> void {
|
||||
timer0.tick();
|
||||
timer1.tick();
|
||||
timer2.tick();
|
||||
|
||||
//TEST register S-SMP speed control
|
||||
//24 clocks have already been added for this cycle at this point
|
||||
switch(status.clock_speed) {
|
||||
case 0: break; //100% speed
|
||||
case 1: add_clocks(24); break; // 50% speed
|
||||
case 2: while(true) add_clocks(24); // 0% speed -- locks S-SMP
|
||||
case 3: add_clocks(24 * 9); break; // 10% speed
|
||||
switch(status.clockSpeed) {
|
||||
case 0: break; //100% speed
|
||||
case 1: addClocks(24); break; // 50% speed
|
||||
case 2: while(true) addClocks(24); // 0% speed -- locks S-SMP
|
||||
case 3: addClocks(24 * 9); break; // 10% speed
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned timer_frequency>
|
||||
void SMP::Timer<timer_frequency>::tick() {
|
||||
template<unsigned Frequency>
|
||||
auto SMP::Timer<Frequency>::tick() -> void {
|
||||
//stage 0 increment
|
||||
stage0_ticks += smp.status.timer_step;
|
||||
if(stage0_ticks < timer_frequency) return;
|
||||
stage0_ticks -= timer_frequency;
|
||||
stage0 += smp.status.timerStep;
|
||||
if(stage0 < Frequency) return;
|
||||
stage0 -= Frequency;
|
||||
|
||||
//stage 1 increment
|
||||
stage1_ticks ^= 1;
|
||||
synchronize_stage1();
|
||||
stage1 ^= 1;
|
||||
synchronizeStage1();
|
||||
}
|
||||
|
||||
template<unsigned timer_frequency>
|
||||
void SMP::Timer<timer_frequency>::synchronize_stage1() {
|
||||
bool new_line = stage1_ticks;
|
||||
if(smp.status.timers_enable == false) new_line = false;
|
||||
if(smp.status.timers_disable == true) new_line = false;
|
||||
template<unsigned Frequency>
|
||||
auto SMP::Timer<Frequency>::synchronizeStage1() -> void {
|
||||
bool newLine = stage1;
|
||||
if(smp.status.timersEnable == false) newLine = false;
|
||||
if(smp.status.timersDisable == true) newLine = false;
|
||||
|
||||
bool old_line = current_line;
|
||||
current_line = new_line;
|
||||
if(old_line != 1 || new_line != 0) return; //only pulse on 1->0 transition
|
||||
bool oldLine = line;
|
||||
line = newLine;
|
||||
if(oldLine != 1 || newLine != 0) return; //only pulse on 1->0 transition
|
||||
|
||||
//stage 2 increment
|
||||
if(enable == false) return;
|
||||
if(++stage2_ticks != target) return;
|
||||
if(++stage2 != target) return;
|
||||
|
||||
//stage 3 increment
|
||||
stage2_ticks = 0;
|
||||
stage3_ticks++;
|
||||
stage2 = 0;
|
||||
stage3++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -14,7 +14,7 @@ void Audio::coprocessor_enable(bool state) {
|
||||
void Audio::coprocessor_frequency(double input_frequency) {
|
||||
dspaudio.setFrequency(input_frequency);
|
||||
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) {
|
||||
|
47
sfc/system/device.cpp
Normal file
47
sfc/system/device.cpp
Normal 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
28
sfc/system/device.hpp
Normal 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;
|
@ -1,39 +0,0 @@
|
||||
#ifdef SYSTEM_CPP
|
||||
|
||||
Input input;
|
||||
|
||||
void Input::connect(bool port, Input::Device id) {
|
||||
Controller*& controller = (port == Controller::Port1 ? port1 : port2);
|
||||
if(controller) {
|
||||
delete controller;
|
||||
controller = nullptr;
|
||||
}
|
||||
|
||||
switch(id) { default:
|
||||
case Device::None: controller = new Controller(port); break;
|
||||
case Device::Joypad: controller = new Gamepad(port); break;
|
||||
case Device::Multitap: controller = new Multitap(port); break;
|
||||
case Device::Mouse: controller = new Mouse(port); break;
|
||||
case Device::SuperScope: controller = new SuperScope(port); break;
|
||||
case Device::Justifier: controller = new Justifier(port, false); break;
|
||||
case Device::Justifiers: controller = new Justifier(port, true); break;
|
||||
case Device::USART: controller = new USART(port); break;
|
||||
}
|
||||
|
||||
switch(port) {
|
||||
case Controller::Port1: configuration.controller_port1 = id; break;
|
||||
case Controller::Port2: configuration.controller_port2 = id; break;
|
||||
}
|
||||
}
|
||||
|
||||
Input::Input() {
|
||||
connect(Controller::Port1, Input::Device::Joypad);
|
||||
connect(Controller::Port2, Input::Device::Joypad);
|
||||
}
|
||||
|
||||
Input::~Input() {
|
||||
if(port1) delete port1;
|
||||
if(port2) delete port2;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,39 +0,0 @@
|
||||
struct Input {
|
||||
enum class Device : unsigned {
|
||||
Joypad,
|
||||
Multitap,
|
||||
Mouse,
|
||||
SuperScope,
|
||||
Justifier,
|
||||
Justifiers,
|
||||
USART,
|
||||
None,
|
||||
};
|
||||
|
||||
enum class JoypadID : unsigned {
|
||||
B = 0, Y = 1, Select = 2, Start = 3,
|
||||
Up = 4, Down = 5, Left = 6, Right = 7,
|
||||
A = 8, X = 9, L = 10, R = 11,
|
||||
};
|
||||
|
||||
enum class MouseID : unsigned {
|
||||
X = 0, Y = 1, Left = 2, Right = 3,
|
||||
};
|
||||
|
||||
enum class SuperScopeID : unsigned {
|
||||
X = 0, Y = 1, Trigger = 2, Cursor = 3, Turbo = 4, Pause = 5,
|
||||
};
|
||||
|
||||
enum class JustifierID : unsigned {
|
||||
X = 0, Y = 1, Trigger = 2, Start = 3,
|
||||
};
|
||||
|
||||
Controller* port1 = nullptr;
|
||||
Controller* port2 = nullptr;
|
||||
|
||||
void connect(bool port, Input::Device id);
|
||||
Input();
|
||||
~Input();
|
||||
};
|
||||
|
||||
extern Input input;
|
@ -1,9 +1,9 @@
|
||||
#ifdef SYSTEM_CPP
|
||||
|
||||
serializer System::serialize() {
|
||||
serializer s(serialize_size);
|
||||
auto System::serialize() -> serializer {
|
||||
serializer s(serializeSize);
|
||||
|
||||
unsigned signature = 0x31545342, version = Info::SerializerVersion;
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512], profile[16];
|
||||
memcpy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
memset(&description, 0, sizeof description);
|
||||
@ -16,12 +16,12 @@ serializer System::serialize() {
|
||||
s.array(description);
|
||||
s.array(profile);
|
||||
|
||||
serialize_all(s);
|
||||
serializeAll(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool System::unserialize(serializer& s) {
|
||||
unsigned signature, version;
|
||||
auto System::unserialize(serializer& s) -> bool {
|
||||
uint signature, version;
|
||||
char hash[64], description[512], profile[16];
|
||||
|
||||
s.integer(signature);
|
||||
@ -35,7 +35,7 @@ bool System::unserialize(serializer& s) {
|
||||
if(strcmp(profile, Emulator::Profile)) return false;
|
||||
|
||||
power();
|
||||
serialize_all(s);
|
||||
serializeAll(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -43,12 +43,12 @@ bool System::unserialize(serializer& s) {
|
||||
//internal
|
||||
//========
|
||||
|
||||
void System::serialize(serializer& s) {
|
||||
s.integer((unsigned&)region);
|
||||
s.integer((unsigned&)expansion);
|
||||
auto System::serialize(serializer& s) -> void {
|
||||
s.integer((uint&)region);
|
||||
s.integer((uint&)expansionPort);
|
||||
}
|
||||
|
||||
void System::serialize_all(serializer& s) {
|
||||
auto System::serializeAll(serializer& s) -> void {
|
||||
cartridge.serialize(s);
|
||||
system.serialize(s);
|
||||
random.serialize(s);
|
||||
@ -78,10 +78,10 @@ void System::serialize_all(serializer& s) {
|
||||
//perform dry-run state save:
|
||||
//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.)
|
||||
void System::serialize_init() {
|
||||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
unsigned signature = 0, version = 0;
|
||||
uint signature = 0, version = 0;
|
||||
char hash[64], profile[16], description[512];
|
||||
|
||||
s.integer(signature);
|
||||
@ -90,8 +90,8 @@ void System::serialize_init() {
|
||||
s.array(profile);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
serialize_size = s.size();
|
||||
serializeAll(s);
|
||||
serializeSize = s.size();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,12 +9,17 @@ Random random;
|
||||
|
||||
#include "video.cpp"
|
||||
#include "audio.cpp"
|
||||
#include "input.cpp"
|
||||
#include "device.cpp"
|
||||
#include "serialization.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.enter();
|
||||
@ -23,35 +28,35 @@ void System::run() {
|
||||
}
|
||||
}
|
||||
|
||||
void System::runtosave() {
|
||||
auto System::runToSave() -> void {
|
||||
if(CPU::Threaded == true) {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::CPU;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
}
|
||||
|
||||
if(SMP::Threaded == true) {
|
||||
scheduler.thread = smp.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
}
|
||||
|
||||
if(PPU::Threaded == true) {
|
||||
scheduler.thread = ppu.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
}
|
||||
|
||||
if(DSP::Threaded == true) {
|
||||
scheduler.thread = dsp.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < cpu.coprocessors.size(); i++) {
|
||||
auto& chip = *cpu.coprocessors[i];
|
||||
scheduler.thread = chip.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
}
|
||||
}
|
||||
|
||||
void System::runthreadtosave() {
|
||||
auto System::runThreadToSave() -> void {
|
||||
while(true) {
|
||||
scheduler.enter();
|
||||
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);
|
||||
|
||||
eboot.init();
|
||||
satellaviewbaseunit.init();
|
||||
|
||||
icd2.init();
|
||||
mcc.init();
|
||||
nss.init();
|
||||
@ -80,20 +87,20 @@ void System::init() {
|
||||
sdd1.init();
|
||||
obc1.init();
|
||||
msu1.init();
|
||||
|
||||
satellaviewcartridge.init();
|
||||
|
||||
video.init();
|
||||
audio.init();
|
||||
|
||||
input.connect(0, configuration.controller_port1);
|
||||
input.connect(1, configuration.controller_port2);
|
||||
device.connect(0, configuration.controllerPort1);
|
||||
device.connect(1, configuration.controllerPort2);
|
||||
}
|
||||
|
||||
void System::term() {
|
||||
auto System::term() -> void {
|
||||
}
|
||||
|
||||
void System::load() {
|
||||
//string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||
auto System::load() -> void {
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
@ -102,13 +109,12 @@ void System::load() {
|
||||
}
|
||||
|
||||
region = configuration.region;
|
||||
expansion = configuration.expansion_port;
|
||||
if(region == Region::Autodetect) {
|
||||
region = (cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL);
|
||||
}
|
||||
|
||||
cpu_frequency = region() == Region::NTSC ? 21477272 : 21281370;
|
||||
apu_frequency = 24607104;
|
||||
expansionPort = configuration.expansionPort;
|
||||
cpuFrequency = region() == Region::NTSC ? 21477272 : 21281370;
|
||||
apuFrequency = 24606720;
|
||||
|
||||
audio.coprocessor_enable(false);
|
||||
|
||||
@ -118,7 +124,9 @@ void System::load() {
|
||||
cpu.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.hasMCC()) mcc.load();
|
||||
if(cartridge.hasNSSDIP()) nss.load();
|
||||
@ -138,11 +146,13 @@ void System::load() {
|
||||
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.load();
|
||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load();
|
||||
|
||||
serialize_init();
|
||||
serializeInit();
|
||||
}
|
||||
|
||||
void System::unload() {
|
||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.unload();
|
||||
auto System::unload() -> void {
|
||||
if(expansionPort() == Device::ID::Satellaview) satellaviewbaseunit.unload();
|
||||
if(expansionPort() == Device::ID::eBoot) eboot.unload();
|
||||
|
||||
if(cartridge.hasICD2()) icd2.unload();
|
||||
if(cartridge.hasMCC()) mcc.unload();
|
||||
if(cartridge.hasNSSDIP()) nss.unload();
|
||||
@ -163,15 +173,17 @@ void System::unload() {
|
||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload();
|
||||
}
|
||||
|
||||
void System::power() {
|
||||
random.seed((unsigned)time(0));
|
||||
auto System::power() -> void {
|
||||
random.seed((uint)time(0));
|
||||
|
||||
cpu.power();
|
||||
smp.power();
|
||||
dsp.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.hasMCC()) mcc.power();
|
||||
if(cartridge.hasNSSDIP()) nss.power();
|
||||
@ -193,13 +205,15 @@ void System::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void System::reset() {
|
||||
auto System::reset() -> void {
|
||||
cpu.reset();
|
||||
smp.reset();
|
||||
dsp.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.hasMCC()) mcc.reset();
|
||||
if(cartridge.hasNSSDIP()) nss.reset();
|
||||
@ -231,21 +245,16 @@ void System::reset() {
|
||||
if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1);
|
||||
|
||||
scheduler.init();
|
||||
input.connect(0, configuration.controller_port1);
|
||||
input.connect(1, configuration.controller_port2);
|
||||
device.connect(0, configuration.controllerPort1);
|
||||
device.connect(1, configuration.controllerPort2);
|
||||
}
|
||||
|
||||
void System::scanline() {
|
||||
auto System::scanline() -> void {
|
||||
video.scanline();
|
||||
if(cpu.vcounter() == 241) scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
||||
}
|
||||
|
||||
void System::frame() {
|
||||
}
|
||||
|
||||
System::System() {
|
||||
region = Region::Autodetect;
|
||||
expansion = ExpansionPortDevice::Satellaview;
|
||||
auto System::frame() -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,63 +1,63 @@
|
||||
struct Interface;
|
||||
|
||||
#include "video.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "device.hpp"
|
||||
|
||||
struct System : property<System> {
|
||||
enum class Region : unsigned { NTSC = 0, PAL = 1, Autodetect = 2 };
|
||||
enum class ExpansionPortDevice : unsigned { None = 0, Satellaview = 1 };
|
||||
enum class Region : uint { NTSC = 0, PAL = 1, Autodetect = 2 };
|
||||
|
||||
void run();
|
||||
void runtosave();
|
||||
System();
|
||||
|
||||
void init();
|
||||
void term();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
auto run() -> void;
|
||||
auto runToSave() -> void;
|
||||
|
||||
void frame();
|
||||
void scanline();
|
||||
auto init() -> void;
|
||||
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)
|
||||
readonly<Region> region;
|
||||
readonly<ExpansionPortDevice> expansion;
|
||||
readonly<unsigned> cpu_frequency;
|
||||
readonly<unsigned> apu_frequency;
|
||||
readonly<unsigned> serialize_size;
|
||||
readonly<Device::ID> expansionPort;
|
||||
|
||||
serializer serialize();
|
||||
bool unserialize(serializer&);
|
||||
readonly<uint> cpuFrequency;
|
||||
readonly<uint> apuFrequency;
|
||||
readonly<uint> serializeSize;
|
||||
|
||||
System();
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
|
||||
private:
|
||||
void runthreadtosave();
|
||||
auto runThreadToSave() -> void;
|
||||
|
||||
void serialize(serializer&);
|
||||
void serialize_all(serializer&);
|
||||
void serialize_init();
|
||||
auto serialize(serializer&) -> void;
|
||||
auto serializeAll(serializer&) -> void;
|
||||
auto serializeInit() -> void;
|
||||
|
||||
friend class Cartridge;
|
||||
friend class Video;
|
||||
friend class Audio;
|
||||
friend class Input;
|
||||
friend class Device;
|
||||
};
|
||||
|
||||
extern System system;
|
||||
|
||||
#include "video.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "input.hpp"
|
||||
|
||||
#include <sfc/scheduler/scheduler.hpp>
|
||||
|
||||
struct Configuration {
|
||||
Input::Device controller_port1 = Input::Device::Joypad;
|
||||
Input::Device controller_port2 = Input::Device::Joypad;
|
||||
System::ExpansionPortDevice expansion_port = System::ExpansionPortDevice::Satellaview;
|
||||
Device::ID controllerPort1 = Device::ID::Gamepad;
|
||||
Device::ID controllerPort2 = Device::ID::Gamepad;
|
||||
Device::ID expansionPort = Device::ID::eBoot;
|
||||
System::Region region = System::Region::Autodetect;
|
||||
bool random = true;
|
||||
};
|
||||
@ -65,21 +65,21 @@ struct Configuration {
|
||||
extern Configuration configuration;
|
||||
|
||||
struct Random {
|
||||
void seed(unsigned seed) {
|
||||
auto seed(uint seed) -> void {
|
||||
iter = seed;
|
||||
}
|
||||
|
||||
unsigned operator()(unsigned result) {
|
||||
auto operator()(uint result) -> uint {
|
||||
if(configuration.random == false) return result;
|
||||
return iter = (iter >> 1) ^ (((iter & 1) - 1) & 0xedb88320);
|
||||
}
|
||||
|
||||
void serialize(serializer& s) {
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer(iter);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned iter = 0;
|
||||
uint iter = 0;
|
||||
};
|
||||
|
||||
extern Random random;
|
||||
|
@ -105,20 +105,20 @@ void Video::draw_cursor(uint16_t color, int x, int y) {
|
||||
}
|
||||
|
||||
void Video::update() {
|
||||
switch(configuration.controller_port2) {
|
||||
case Input::Device::SuperScope:
|
||||
if(dynamic_cast<SuperScope*>(input.port2)) {
|
||||
SuperScope &device = (SuperScope&)*input.port2;
|
||||
draw_cursor(0x7c00, device.x, device.y);
|
||||
switch(configuration.controllerPort2) {
|
||||
case Device::ID::SuperScope:
|
||||
if(dynamic_cast<SuperScope*>(device.controllerPort2)) {
|
||||
SuperScope& controller = (SuperScope&)*device.controllerPort2;
|
||||
draw_cursor(0x7c00, controller.x, controller.y);
|
||||
}
|
||||
break;
|
||||
case Input::Device::Justifier:
|
||||
case Input::Device::Justifiers:
|
||||
if(dynamic_cast<Justifier*>(input.port2)) {
|
||||
Justifier &device = (Justifier&)*input.port2;
|
||||
draw_cursor(0x001f, device.player1.x, device.player1.y);
|
||||
if(device.chained == false) break;
|
||||
draw_cursor(0x02e0, device.player2.x, device.player2.y);
|
||||
case Device::ID::Justifier:
|
||||
case Device::ID::Justifiers:
|
||||
if(dynamic_cast<Justifier*>(device.controllerPort2)) {
|
||||
Justifier& controller = (Justifier&)*device.controllerPort2;
|
||||
draw_cursor(0x001f, controller.player1.x, controller.player1.y);
|
||||
if(!controller.chained) break;
|
||||
draw_cursor(0x02e0, controller.player2.x, controller.player2.y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -115,11 +115,12 @@ auto Presentation::updateEmulator() -> void {
|
||||
resetSystem.setVisible(emulator->information.resettable);
|
||||
inputPort1.setVisible(false).reset();
|
||||
inputPort2.setVisible(false).reset();
|
||||
inputPort3.setVisible(false).reset();
|
||||
|
||||
for(auto n : range(emulator->port)) {
|
||||
if(n >= 2) break;
|
||||
if(n >= 3) break;
|
||||
auto& port = emulator->port[n];
|
||||
auto& menu = (n == 0 ? inputPort1 : inputPort2);
|
||||
auto& menu = (n == 0 ? inputPort1 : n == 1 ? inputPort2 : inputPort3);
|
||||
menu.setText(port.name);
|
||||
|
||||
Group devices;
|
||||
@ -133,7 +134,7 @@ auto Presentation::updateEmulator() -> void {
|
||||
if(devices.objectCount() > 1) menu.setVisible();
|
||||
}
|
||||
|
||||
systemMenuSeparatorPorts.setVisible(inputPort1.visible() || inputPort2.visible());
|
||||
systemMenuSeparatorPorts.setVisible(inputPort1.visible() || inputPort2.visible() || inputPort3.visible());
|
||||
}
|
||||
|
||||
auto Presentation::resizeViewport() -> void {
|
||||
|
@ -15,6 +15,7 @@ struct Presentation : Window {
|
||||
MenuSeparator systemMenuSeparatorPorts{&systemMenu};
|
||||
Menu inputPort1{&systemMenu};
|
||||
Menu inputPort2{&systemMenu};
|
||||
Menu inputPort3{&systemMenu};
|
||||
MenuSeparator systemMenuSeparatorUnload{&systemMenu};
|
||||
MenuItem unloadSystem{&systemMenu};
|
||||
Menu settingsMenu{&menuBar};
|
||||
|
Loading…
Reference in New Issue
Block a user