bsnes/higan/fc/fc.hpp

48 lines
1.2 KiB
C++
Raw Normal View History

#pragma once
Update to v082r04 release. byuu says: So, here's the deal. I now have three emulators. I don't think the NES/GB ones are at all useful, but I do want them to be eventually. And having them have those pathetic little GUIs like ui-gameboy, and keeping everything in separate project folders, just doesn't work well for me. I kind of "got around" the issue with the Game Boy, by only allowing SGB mode emulation. But there is no "Super Nintendo" ... er ... wait ... uhmm ... well, you know what I mean anyway. So, my idea is to write a multi-emulator GUI, and keep the projects together. The GUI is not going to change much. The way I envision this working: At startup, you have a menubar with: "Cartridge, Settings, Tools, Help". Cartridge has "Load NES Cartridge", "Load SNES Cartridge", etc. When you load something, Cartridge is replaced with the appropriate system menu, eg "SNES". Here you have all your regular items: "power, reset, controller port selection, etc." There is also a new "Unload Cartridge" option, which is how you restore the "Cartridge" menu again. I have no plans to emulate any other systems, but if I ever do emulate something that doesn't take cartridges, I'll change the name to just "Load" or something. The cheat editor / state manager will look and act exactly the same. The settings panel will look exactly the same. I'll simply show/hide system-specific options as needed, like NES/SNES aspect ratio correction, etc. The input mapping window will just have settings for the currently loaded system. Video and audio tweaking will apply cross-system, as will hotkey mapping. The GUI stuff is mostly copy-paste, so it should only take me a week to get it 95% back to where it was, so don't worry, this isn't total GUI rewrite #80. I am, however, making all the objects pointers, so that I can destruct them all prior to main() returning, which is certainly one way of fixing that annoying Windows/Qt crash. Please only test on Linux. The Windows port is broken to hell, and will give you a bad impression of the idea: - menu groups are not hiding for some reason (all groups are showing, it looks hideous) - Timer interval(0) is taking 16ms per call, capping the FPS to ~64 tops [FWIW, bsnes/accuracy gets 130fps, bgameboy gets 450fps, bnes gets 800fps; all run at lowest possible granularity] - the OS keeps beeping when you press keys (AGAIN) Of course, Qt and GTK+ don't let you shrink a window from the requested geometry size, because they suck. So the video scaling stuff doesn't work all that great yet. Man, a metric fuckton of things need to be fixed in phoenix, and I really don't know how to fix any of them :/
2011-09-09 04:08:38 +00:00
//license: GPLv3
//started: 2011-09-05
#include <emulator/emulator.hpp>
#include <emulator/thread.hpp>
#include <emulator/scheduler.hpp>
#include <emulator/cheat.hpp>
#include <processor/mos6502/mos6502.hpp>
namespace Famicom {
#define platform Emulator::platform
namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler;
using Cheat = Emulator::Cheat;
extern Scheduler scheduler;
extern Cheat cheat;
Update to v082r04 release. byuu says: So, here's the deal. I now have three emulators. I don't think the NES/GB ones are at all useful, but I do want them to be eventually. And having them have those pathetic little GUIs like ui-gameboy, and keeping everything in separate project folders, just doesn't work well for me. I kind of "got around" the issue with the Game Boy, by only allowing SGB mode emulation. But there is no "Super Nintendo" ... er ... wait ... uhmm ... well, you know what I mean anyway. So, my idea is to write a multi-emulator GUI, and keep the projects together. The GUI is not going to change much. The way I envision this working: At startup, you have a menubar with: "Cartridge, Settings, Tools, Help". Cartridge has "Load NES Cartridge", "Load SNES Cartridge", etc. When you load something, Cartridge is replaced with the appropriate system menu, eg "SNES". Here you have all your regular items: "power, reset, controller port selection, etc." There is also a new "Unload Cartridge" option, which is how you restore the "Cartridge" menu again. I have no plans to emulate any other systems, but if I ever do emulate something that doesn't take cartridges, I'll change the name to just "Load" or something. The cheat editor / state manager will look and act exactly the same. The settings panel will look exactly the same. I'll simply show/hide system-specific options as needed, like NES/SNES aspect ratio correction, etc. The input mapping window will just have settings for the currently loaded system. Video and audio tweaking will apply cross-system, as will hotkey mapping. The GUI stuff is mostly copy-paste, so it should only take me a week to get it 95% back to where it was, so don't worry, this isn't total GUI rewrite #80. I am, however, making all the objects pointers, so that I can destruct them all prior to main() returning, which is certainly one way of fixing that annoying Windows/Qt crash. Please only test on Linux. The Windows port is broken to hell, and will give you a bad impression of the idea: - menu groups are not hiding for some reason (all groups are showing, it looks hideous) - Timer interval(0) is taking 16ms per call, capping the FPS to ~64 tops [FWIW, bsnes/accuracy gets 130fps, bgameboy gets 450fps, bnes gets 800fps; all run at lowest possible granularity] - the OS keeps beeping when you press keys (AGAIN) Of course, Qt and GTK+ don't let you shrink a window from the requested geometry size, because they suck. So the video scaling stuff doesn't work all that great yet. Man, a metric fuckton of things need to be fixed in phoenix, and I really don't know how to fix any of them :/
2011-09-09 04:08:38 +00:00
Update to v100r14 release. byuu says: (Windows: compile with -fpermissive to silence an annoying error. I'll fix it in the next WIP.) I completely replaced the time management system in higan and overhauled the scheduler. Before, processor threads would have "int64 clock"; and there would be a 1:1 relationship between two threads. When thread A ran for X cycles, it'd subtract X * B.Frequency from clock; and when thread B ran for Y cycles, it'd add Y * A.Frequency from clock. This worked well and allowed perfect precision; but it doesn't work when you have more complicated relationships: eg the 68K can sync to the Z80 and PSG; the Z80 to the 68K and PSG; so the PSG needs two counters. The new system instead uses a "uint64 clock" variable that represents time in attoseconds. Every time the scheduler exits, it subtracts the smallest clock count from all threads, to prevent an overflow scenario. The only real downside is that rounding errors mean that roughly every 20 minutes, we have a rounding error of one clock cycle (one 20,000,000th of a second.) However, this only applies to systems with multiple oscillators, like the SNES. And when you're in that situation ... there's no such thing as a perfect oscillator anyway. A real SNES will be thousands of times less out of spec than 1hz per 20 minutes. The advantages are pretty immense. First, we obviously can now support more complex relationships between threads. Second, we can build a much more abstracted scheduler. All of libco is now abstracted away completely, which may permit a state-machine / coroutine version of Thread in the future. We've basically gone from this: auto SMP::step(uint clocks) -> void { clock += clocks * (uint64)cpu.frequency; dsp.clock -= clocks; if(dsp.clock < 0 && !scheduler.synchronizing()) co_switch(dsp.thread); if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread); } To this: auto SMP::step(uint clocks) -> void { Thread::step(clocks); synchronize(dsp); synchronize(cpu); } As you can see, we don't have to do multiple clock adjustments anymore. This is a huge win for the SNES CPU that had to update the SMP, DSP, all peripherals and all coprocessors. Likewise, we don't have to synchronize all coprocessors when one runs, now we can just synchronize the active one to the CPU. Third, when changing the frequencies of threads (think SGB speed setting modes, GBC double-speed mode, etc), it no longer causes the "int64 clock" value to be erroneous. Fourth, this results in a fairly decent speedup, mostly across the board. Aside from the GBA being mostly a wash (for unknown reasons), it's about an 8% - 12% speedup in every other emulation core. Now, all of this said ... this was an unbelievably massive change, so ... you know what that means >_> If anyone can help test all types of SNES coprocessors, and some other system games, it'd be appreciated. ---- Lastly, we have a bitchin' new about screen. It unfortunately adds ~200KiB onto the binary size, because the PNG->C++ header file transformation doesn't compress very well, and I want to keep the original resource files in with the higan archive. I might try some things to work around this file size increase in the future, but for now ... yeah, slightly larger archive sizes, sorry. The logo's a bit busted on Windows (the Label control's background transparency and alignment settings aren't working), but works well on GTK. I'll have to fix Windows before the next official release. For now, look on my Twitter feed if you want to see what it's supposed to look like. ---- EDIT: forgot about ICD2::Enter. It's doing some weird inverse run-to-save thing that I need to implement support for somehow. So, save states on the SGB core probably won't work with this WIP.
2016-07-30 03:56:12 +00:00
struct Thread : Emulator::Thread {
Update to v100r15 release. byuu wrote: Aforementioned scheduler changes added. Longer explanation of why here: http://hastebin.com/raw/toxedenece Again, we really need to test this as thoroughly as possible for regressions :/ This is a really major change that affects absolutely everything: all emulation cores, all coprocessors, etc. Also added ADDX and SUB to the 68K core, which brings us just barely above 50% of the instruction encoding space completed. [Editor's note: The "aformentioned scheduler changes" were described in a previous forum post: Unfortunately, 64-bits just wasn't enough precision (we were getting misalignments ~230 times a second on 21/24MHz clocks), so I had to move to 128-bit counters. This of course doesn't exist on 32-bit architectures (and probably not on all 64-bit ones either), so for now ... higan's only going to compile on 64-bit machines until we figure something out. Maybe we offer a "lower precision" fallback for machines that lack uint128_t or something. Using the booth algorithm would be way too slow. Anyway, the precision is now 2^-96, which is roughly 10^-29. That puts us far beyond the yoctosecond. Suck it, MAME :P I'm jokingly referring to it as the byuusecond. The other 32-bits of precision allows a 1Hz clock to run up to one full second before all clocks need to be normalized to prevent overflow. I fixed a serious wobbling issue where I was using clock > other.clock for synchronization instead of clock >= other.clock; and also another aliasing issue when two threads share a common frequency, but don't run in lock-step. The latter I don't even fully understand, but I did observe it in testing. nall/serialization.hpp has been extended to support 128-bit integers, but without explicitly naming them (yay generic code), so nall will still compile on 32-bit platforms for all other applications. Speed is basically a wash now. FC's a bit slower, SFC's a bit faster. The "longer explanation" in the linked hastebin is: Okay, so the idea is that we can have an arbitrary number of oscillators. Take the SNES: - CPU/PPU clock = 21477272.727272hz - SMP/DSP clock = 24576000hz - Cartridge DSP1 clock = 8000000hz - Cartridge MSU1 clock = 44100hz - Controller Port 1 modem controller clock = 57600hz - Controller Port 2 barcode battler clock = 115200hz - Expansion Port exercise bike clock = 192000hz Is this a pathological case? Of course it is, but it's possible. The first four do exist in the wild already: see Rockman X2 MSU1 patch. Manifest files with higan let you specify any frequency you want for any component. The old trick higan used was to hold an int64 counter for each thread:thread synchronization, and adjust it like so: - if thread A steps X clocks; then clock += X * threadB.frequency - if clock >= 0; switch to threadB - if thread B steps X clocks; then clock -= X * threadA.frequency - if clock < 0; switch to threadA But there are also system configurations where one processor has to synchronize with more than one other processor. Take the Genesis: - the 68K has to sync with the Z80 and PSG and YM2612 and VDP - the Z80 has to sync with the 68K and PSG and YM2612 - the PSG has to sync with the 68K and Z80 and YM2612 Now I could do this by having an int64 clock value for every association. But these clock values would have to be outside the individual Thread class objects, and we would have to update every relationship's clock value. So the 68K would have to update the Z80, PSG, YM2612 and VDP clocks. That's four expensive 64-bit multiply-adds per clock step event instead of one. As such, we have to account for both possibilities. The only way to do this is with a single time base. We do this like so: - setup: scalar = timeBase / frequency - step: clock += scalar * clocks Once per second, we look at every thread, find the smallest clock value. Then subtract that value from all threads. This prevents the clock counters from overflowing. Unfortunately, these oscillator values are psychotic, unpredictable, and often times repeating fractions. Even with a timeBase of 1,000,000,000,000,000,000 (one attosecond); we get rounding errors every ~16,300 synchronizations. Specifically, this happens with a CPU running at 21477273hz (rounded) and SMP running at 24576000hz. That may be good enough for most emulators, but ... you know how I am. Plus, even at the attosecond level, we're really pushing against the limits of 64-bit integers. Given the reciprocal inverse, a frequency of 1Hz (which does exist in higan!) would have a scalar that consumes 1/18th of the entire range of a uint64 on every single step. Yes, I could raise the frequency, and then step by that amount, I know. But I don't want to have weird gotchas like that in the scheduler core. Until I increase the accuracy to about 100 times greater than a yoctosecond, the rounding errors are too great. And since the only choice above 64-bit values is 128-bit values; we might as well use all the extra headroom. 2^-96 as a timebase gives me the ability to have both a 1Hz and 4GHz clock; and run them both for a full second; before an overflow event would occur. Another hastebin includes demonstration code: #include <libco/libco.h> #include <nall/nall.hpp> using namespace nall; // cothread_t mainThread = nullptr; const uint iterations = 100'000'000; const uint cpuFreq = 21477272.727272 + 0.5; const uint smpFreq = 24576000.000000 + 0.5; const uint cpuStep = 4; const uint smpStep = 5; // struct ThreadA { cothread_t handle = nullptr; uint64 frequency = 0; int64 clock = 0; auto create(auto (*entrypoint)() -> void, uint frequency) { this->handle = co_create(65536, entrypoint); this->frequency = frequency; this->clock = 0; } }; struct CPUA : ThreadA { static auto Enter() -> void; auto main() -> void; CPUA() { create(&CPUA::Enter, cpuFreq); } } cpuA; struct SMPA : ThreadA { static auto Enter() -> void; auto main() -> void; SMPA() { create(&SMPA::Enter, smpFreq); } } smpA; uint8 queueA[iterations]; uint offsetA; cothread_t resumeA = cpuA.handle; auto EnterA() -> void { offsetA = 0; co_switch(resumeA); } auto QueueA(uint value) -> void { queueA[offsetA++] = value; if(offsetA >= iterations) { resumeA = co_active(); co_switch(mainThread); } } auto CPUA::Enter() -> void { while(true) cpuA.main(); } auto CPUA::main() -> void { QueueA(1); smpA.clock -= cpuStep * smpA.frequency; if(smpA.clock < 0) co_switch(smpA.handle); } auto SMPA::Enter() -> void { while(true) smpA.main(); } auto SMPA::main() -> void { QueueA(2); smpA.clock += smpStep * cpuA.frequency; if(smpA.clock >= 0) co_switch(cpuA.handle); } // struct ThreadB { cothread_t handle = nullptr; uint128_t scalar = 0; uint128_t clock = 0; auto print128(uint128_t value) { string s; while(value) { s.append((char)('0' + value % 10)); value /= 10; } s.reverse(); print(s, "\n"); } //femtosecond (10^15) = 16306 //attosecond (10^18) = 688838 //zeptosecond (10^21) = 13712691 //yoctosecond (10^24) = 13712691 (hitting a dead-end on a rounding error causing a wobble) //byuusecond? ( 2^96) = (perfect? 79,228 times more precise than a yoctosecond) auto create(auto (*entrypoint)() -> void, uint128_t frequency) { this->handle = co_create(65536, entrypoint); uint128_t unitOfTime = 1; //for(uint n : range(29)) unitOfTime *= 10; unitOfTime <<= 96; //2^96 time units ... this->scalar = unitOfTime / frequency; print128(this->scalar); this->clock = 0; } auto step(uint128_t clocks) -> void { clock += clocks * scalar; } auto synchronize(ThreadB& thread) -> void { if(clock >= thread.clock) co_switch(thread.handle); } }; struct CPUB : ThreadB { static auto Enter() -> void; auto main() -> void; CPUB() { create(&CPUB::Enter, cpuFreq); } } cpuB; struct SMPB : ThreadB { static auto Enter() -> void; auto main() -> void; SMPB() { create(&SMPB::Enter, smpFreq); clock = 1; } } smpB; auto correct() -> void { auto minimum = min(cpuB.clock, smpB.clock); cpuB.clock -= minimum; smpB.clock -= minimum; } uint8 queueB[iterations]; uint offsetB; cothread_t resumeB = cpuB.handle; auto EnterB() -> void { correct(); offsetB = 0; co_switch(resumeB); } auto QueueB(uint value) -> void { queueB[offsetB++] = value; if(offsetB >= iterations) { resumeB = co_active(); co_switch(mainThread); } } auto CPUB::Enter() -> void { while(true) cpuB.main(); } auto CPUB::main() -> void { QueueB(1); step(cpuStep); synchronize(smpB); } auto SMPB::Enter() -> void { while(true) smpB.main(); } auto SMPB::main() -> void { QueueB(2); step(smpStep); synchronize(cpuB); } // #include <nall/main.hpp> auto nall::main(string_vector) -> void { mainThread = co_active(); uint masterCounter = 0; while(true) { print(masterCounter++, " ...\n"); auto A = clock(); EnterA(); auto B = clock(); print((double)(B - A) / CLOCKS_PER_SEC, "s\n"); auto C = clock(); EnterB(); auto D = clock(); print((double)(D - C) / CLOCKS_PER_SEC, "s\n"); for(uint n : range(iterations)) { if(queueA[n] != queueB[n]) return print("fail at ", n, "\n"); } } } ...and that's everything.]
2016-07-31 02:11:20 +00:00
auto create(auto (*entrypoint)() -> void, double frequency) -> void {
Emulator::Thread::create(entrypoint, frequency);
scheduler.append(*this);
}
inline auto synchronize(Thread& thread) -> void {
if(clock() >= thread.clock()) scheduler.resume(thread);
}
};
Update to v102r28 release. byuu says: Changelog: - higan: `Emulator::<Platform::load>()` now returns a struct containing both a path ID and a string option - higan: `Emulator::<Platform::load>()` now takes an optional final argument of string options - fc: added PAL emulation (finally, only took six years) - md: added PAL emulation - md: fixed address parameter to `VDP::Sprite::write()`; fixes missing sprites in Super Street Fighter II - md: emulated HIRQ counter; fixes many games - Super Street Fighter II - status bar - Altered Beast - status bar - Sonic the Hedgehog - Labyrinth Zone - water effect - etc. - ms: added PAL emulation - sfc: added the ability to override the default region auto-detection - sfc: removed "system.region" override setting from `Super Famicom.sys` - tomoko: added options list to game folder load dialog window - tomoko: added the ability to specify game folder load options on the command-line So, basically ... Sega forced a change with the way region detection works. You end up with games that can run on multiple regions, and the content changes accordingly. Bare Knuckle in NTSC-J mode will become Streets of Rage in NTSC-U mode. Some games can even run in both NTSC and PAL mode. In my view, there should be a separate ROM for each region a game was released in, even if the ROM content were identical. But unfortunately that's not how things were done by anyone else. So to support this, the higan load dialog now has a drop-down at the bottom-right, where you can choose the region to load games from. On the SNES, it defaults to "Auto", which will pull the region setting from the manifest, or fall back on NTSC. On the Mega Drive ... unfortunately, I can't auto-detect the region from the ROM header. $1f0 is supposed to contain a string like "JUE", but instead you get games like Maui Mallard that put an "A" there, and other such nonsense. Sega was far more lax than Nintendo with the ROM header validity. So for now at least, you have to manually select your region every time you play a Mega Drive game, thus you have "NTSC-J", "NTSC-U", and "PAL". The same goes for the Master System for the same reason, but there's only "NTSC" and "PAL" here. I'm not sure if games have a way to detect domestic vs international consoles. And for now ... the Famicom is the same as well, with no auto-detection. I'd sincerely hope iNES has a header bit for the region, but I didn't bother with updating icarus to support that yet. The way to pass these parameters on the command-line is to prefix the game path with "option:", so for example:    higan "PAL:/path/to/Sonic the Hedgehog (USA, Europe).md" If you don't provide a prefix, it uses the default (NTSC-J, NTSC, or Auto.) Obviously, it's not possible to pass parameters with drag-and-drop, so you will always get the default option in said case.
2017-06-20 12:34:50 +00:00
struct Region {
Update to v103r01 release. byuu says: Changelog: - nall/dsp: improve one pole coefficient calculations [Fatbag] - higan/audio: reworked filters to support selection of either one pole (first-order) or biquad (second-order) filters - note: the design is not stable yet; so forks should not put too much effort into synchronizing with this change yet - fc: added first-order filters as per NESdev wiki (90hz lowpass + 440hz lowpass + 14khz highpass) - fc: created separate NTSC-J and NTSC-U regions - NESdev wiki says the Japanese Famicom uses a separate audio filtering strategy, but details are fuzzy - there's also cartridge audio output being disabled on NES units; and differences with controllers - this stuff will be supported in the future, just adding the support for it now - gba: corrected serious bugs in PSG wave channel emulation [Cydrak] - note that if there are still bugs here, it's my fault - md/psg,ym2612: added first-order low-pass 2840hz filter to match VA3-VA6 Mega Drives - md/psg: lowered volume relative to the YM2612 - using 0x1400; multiple people agreed it was the closest to the hardware recordings against a VA6 - ms,md/psg: don't serialize the volume levels array - md/vdp: Hblank bit acts the same during Vblank as outside of it (it isn't always set during Vblank) - md/vdp: return isPAL in bit 0 of control port reads - tomoko: change command-line option separator from : to | - [Editor's note: This change was present in the public v103, but it's in this changelog because it was made after the v103 WIP] - higan/all: change the 20hz high-pass filters from second-order three-pass to first-order one-pass - these filters are meant to remove DC bias, but I honestly can't hear a difference with or without them - so there's really no sense wasting CPU power with an extremely powerful filter here Things I did not do: - change icarus install rule - work on 8-bit Mega Drive SRAM - work on Famicom or Mega Drive region detection heuristics in icarus My long-term dream plan is to devise a special user-configurable filtering system where you can set relative volumes and create your own list of filters (any number of them in any order at any frequency), that way people can make the systems sound however they want. Right now, the sanest place to put this information is inside the $system.sys/manifest.bml files. But that's not very user friendly, and upgrading to new versions will lose these changes if you don't copy them over manually. Of course, cluttering the GUI with a fancy filter editor is probably supreme overkill for 99% of users, so maybe that's fine.
2017-06-26 01:41:58 +00:00
static inline auto NTSCJ() -> bool;
static inline auto NTSCU() -> bool;
Update to v102r28 release. byuu says: Changelog: - higan: `Emulator::<Platform::load>()` now returns a struct containing both a path ID and a string option - higan: `Emulator::<Platform::load>()` now takes an optional final argument of string options - fc: added PAL emulation (finally, only took six years) - md: added PAL emulation - md: fixed address parameter to `VDP::Sprite::write()`; fixes missing sprites in Super Street Fighter II - md: emulated HIRQ counter; fixes many games - Super Street Fighter II - status bar - Altered Beast - status bar - Sonic the Hedgehog - Labyrinth Zone - water effect - etc. - ms: added PAL emulation - sfc: added the ability to override the default region auto-detection - sfc: removed "system.region" override setting from `Super Famicom.sys` - tomoko: added options list to game folder load dialog window - tomoko: added the ability to specify game folder load options on the command-line So, basically ... Sega forced a change with the way region detection works. You end up with games that can run on multiple regions, and the content changes accordingly. Bare Knuckle in NTSC-J mode will become Streets of Rage in NTSC-U mode. Some games can even run in both NTSC and PAL mode. In my view, there should be a separate ROM for each region a game was released in, even if the ROM content were identical. But unfortunately that's not how things were done by anyone else. So to support this, the higan load dialog now has a drop-down at the bottom-right, where you can choose the region to load games from. On the SNES, it defaults to "Auto", which will pull the region setting from the manifest, or fall back on NTSC. On the Mega Drive ... unfortunately, I can't auto-detect the region from the ROM header. $1f0 is supposed to contain a string like "JUE", but instead you get games like Maui Mallard that put an "A" there, and other such nonsense. Sega was far more lax than Nintendo with the ROM header validity. So for now at least, you have to manually select your region every time you play a Mega Drive game, thus you have "NTSC-J", "NTSC-U", and "PAL". The same goes for the Master System for the same reason, but there's only "NTSC" and "PAL" here. I'm not sure if games have a way to detect domestic vs international consoles. And for now ... the Famicom is the same as well, with no auto-detection. I'd sincerely hope iNES has a header bit for the region, but I didn't bother with updating icarus to support that yet. The way to pass these parameters on the command-line is to prefix the game path with "option:", so for example:    higan "PAL:/path/to/Sonic the Hedgehog (USA, Europe).md" If you don't provide a prefix, it uses the default (NTSC-J, NTSC, or Auto.) Obviously, it's not possible to pass parameters with drag-and-drop, so you will always get the default option in said case.
2017-06-20 12:34:50 +00:00
static inline auto PAL() -> bool;
};
#include <fc/controller/controller.hpp>
#include <fc/system/system.hpp>
#include <fc/memory/memory.hpp>
#include <fc/cartridge/cartridge.hpp>
#include <fc/cpu/cpu.hpp>
#include <fc/apu/apu.hpp>
#include <fc/ppu/ppu.hpp>
Update to v082r04 release. byuu says: So, here's the deal. I now have three emulators. I don't think the NES/GB ones are at all useful, but I do want them to be eventually. And having them have those pathetic little GUIs like ui-gameboy, and keeping everything in separate project folders, just doesn't work well for me. I kind of "got around" the issue with the Game Boy, by only allowing SGB mode emulation. But there is no "Super Nintendo" ... er ... wait ... uhmm ... well, you know what I mean anyway. So, my idea is to write a multi-emulator GUI, and keep the projects together. The GUI is not going to change much. The way I envision this working: At startup, you have a menubar with: "Cartridge, Settings, Tools, Help". Cartridge has "Load NES Cartridge", "Load SNES Cartridge", etc. When you load something, Cartridge is replaced with the appropriate system menu, eg "SNES". Here you have all your regular items: "power, reset, controller port selection, etc." There is also a new "Unload Cartridge" option, which is how you restore the "Cartridge" menu again. I have no plans to emulate any other systems, but if I ever do emulate something that doesn't take cartridges, I'll change the name to just "Load" or something. The cheat editor / state manager will look and act exactly the same. The settings panel will look exactly the same. I'll simply show/hide system-specific options as needed, like NES/SNES aspect ratio correction, etc. The input mapping window will just have settings for the currently loaded system. Video and audio tweaking will apply cross-system, as will hotkey mapping. The GUI stuff is mostly copy-paste, so it should only take me a week to get it 95% back to where it was, so don't worry, this isn't total GUI rewrite #80. I am, however, making all the objects pointers, so that I can destruct them all prior to main() returning, which is certainly one way of fixing that annoying Windows/Qt crash. Please only test on Linux. The Windows port is broken to hell, and will give you a bad impression of the idea: - menu groups are not hiding for some reason (all groups are showing, it looks hideous) - Timer interval(0) is taking 16ms per call, capping the FPS to ~64 tops [FWIW, bsnes/accuracy gets 130fps, bgameboy gets 450fps, bnes gets 800fps; all run at lowest possible granularity] - the OS keeps beeping when you press keys (AGAIN) Of course, Qt and GTK+ don't let you shrink a window from the requested geometry size, because they suck. So the video scaling stuff doesn't work all that great yet. Man, a metric fuckton of things need to be fixed in phoenix, and I really don't know how to fix any of them :/
2011-09-09 04:08:38 +00:00
}
#include <fc/interface/interface.hpp>