Compare commits

..

No commits in common. "master" and "1" have entirely different histories.
master ... 1

27 changed files with 199 additions and 227 deletions

View file

@ -1,52 +0,0 @@
# bsnes-classic
This fork of bsnes-classic also includes perfect emulation of Super FX and Super FX 2 games as well as an experimental upscaling 6xBRZ filter for OpenGL. All courtesy of Zenju, CarterLi and awjackson.
## Building on Windows (64-bit)
- Get mingw-w64 with 64-bit Qt 4.8.6 and do a full installation of the exe (https://sourceforge.net/projects/qt64ng/files/qt/x86-64/4.8.6/mingw-4.9/seh/)
- Set following environment variables (right click on My Computer, then Properties, Advanced, Environment variables): 
QTDIR to C:\Qt\4.X.X (or whatever path you installed QT)
QMAKESPEC to win32-g++
and adjust PATH, add C:\Qt\4.X.X\bin and C:\MinGW\bin (or whatever path you installed MinGW)
- Logout/login or restart after changing environment variables, otherwise it won't work
- Run the terminal from minGW in the start menu and navigate to the Makefiles
- Run `mingw32-make`
Building with the original MinGW used to be the preferred way to do it, but made building "out of the box" annoying for various reasons (including requiring outdated DirectX headers/libs and problems with some native Windows code) and is no longer supported.
## Building on OS X
- Install a C++ toolchain ([Xcode](https://developer.apple.com) is probably the easiest route)
- Install Qt 4.8 (get [Brew](http://brew.sh) and run `brew install qt`)
- Make sure the `qtpath` environment variable points to your Qt installation, ie. add `export qtpath=/usr/local/Cellar/qt/4.8.7_2` to .bash_profile.
- Run `make`from the bsnes directory.
If you're running macOS 10.12 Sierra you will (probably not) be able to install Qt4 using brew. If so, try installing this unofficial branch:
```
brew install cartr/qt4/qt
brew linkapps qt
```
## Building on Linux / other *nix
As there is no ``configure`` step, make sure necessary Qt4/X11 packages are installed. On a Debian/Ubuntu system, it would require a command like:
```
apt-get install libqt4-dev libqt4-dev-bin libxv-dev libsdl1.2-dev libao-dev
libopenal-dev g++
```
Afterwards, run ``make`` and if everything works out correctly you will find the output binary in the ``out/`` directory.
The snesfilter, snesreader, and supergameboy plugins can all be built by running make (or mingw32-make) after you've configured your environment to build bsnes itself.
After building, just copy the .dll, .so, or .dylib files into the same directory as bsnes itself.
This fork of bsnes doesn't include the alternate UI based on byuu's `phoenix` library. The purpose of this fork is primarily to add additional UI functionality and I have no intention of implementing every new feature twice using completely different libraries just to keep both versions of the UI at parity.
bsnes v073 and its derivatives are licensed under the GPL v2; see *Help > License ...* for more information.
## Contributors
See *Help > Documentation ...* for a list of authors.

View file

@ -11,7 +11,7 @@
namespace nall { namespace nall {
struct Keyboard; struct Keyboard;
Keyboard keyboard(unsigned = 0); Keyboard& keyboard(unsigned = 0);
static const char KeyboardScancodeName[][64] = { static const char KeyboardScancodeName[][64] = {
"Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
@ -122,9 +122,12 @@ struct Keyboard {
Keyboard(unsigned ID_) : ID(ID_) {} Keyboard(unsigned ID_) : ID(ID_) {}
}; };
inline Keyboard keyboard(unsigned id) { inline Keyboard& keyboard(unsigned id) {
assert(id < Keyboard::Count); static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
return Keyboard(id); switch(id) { default:
case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
}
} }
static const char MouseScancodeName[][64] = { static const char MouseScancodeName[][64] = {
@ -133,7 +136,7 @@ static const char MouseScancodeName[][64] = {
}; };
struct Mouse; struct Mouse;
Mouse mouse(unsigned = 0); Mouse& mouse(unsigned = 0);
struct Mouse { struct Mouse {
const unsigned ID; const unsigned ID;
@ -217,9 +220,12 @@ struct Mouse {
Mouse(unsigned ID_) : ID(ID_) {} Mouse(unsigned ID_) : ID(ID_) {}
}; };
inline Mouse mouse(unsigned id) { inline Mouse& mouse(unsigned id) {
assert(id < Mouse::Count); static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
return Mouse(id); switch(id) { default:
case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
}
} }
static const char JoypadScancodeName[][64] = { static const char JoypadScancodeName[][64] = {
@ -233,7 +239,7 @@ static const char JoypadScancodeName[][64] = {
}; };
struct Joypad; struct Joypad;
Joypad joypad(unsigned = 0); Joypad& joypad(unsigned = 0);
struct Joypad { struct Joypad {
const unsigned ID; const unsigned ID;
@ -339,9 +345,12 @@ struct Joypad {
Joypad(unsigned ID_) : ID(ID_) {} Joypad(unsigned ID_) : ID(ID_) {}
}; };
inline Joypad joypad(unsigned id) { inline Joypad& joypad(unsigned id) {
assert(id < Joypad::Count); static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
return Joypad(id); switch(id) { default:
case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
}
} }
struct Scancode { struct Scancode {

View file

@ -40,7 +40,7 @@ static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, // 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80,
// 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, // 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF,
@ -856,7 +856,6 @@ void SPC_DSP::soft_reset_common()
void SPC_DSP::soft_reset() void SPC_DSP::soft_reset()
{ {
REG(flg) = 0xE0; REG(flg) = 0xE0;
REG(endx) = 0xFF;
soft_reset_common(); soft_reset_common();
} }

View file

@ -111,9 +111,8 @@ void PPU::mmio_w210d(uint8 value) {
regs.m7_hofs = (value << 8) | regs.m7_latch; regs.m7_hofs = (value << 8) | regs.m7_latch;
regs.m7_latch = value; regs.m7_latch = value;
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ppu1ofslatch & ~7) | (regs.bg_ppu2ofslatch & 7); regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG1] >> 8) & 7);
regs.bg_ppu1ofslatch = value; regs.bg_ofslatch = value;
regs.bg_ppu2ofslatch = value;
} }
//BG1VOFS //BG1VOFS
@ -121,47 +120,44 @@ void PPU::mmio_w210e(uint8 value) {
regs.m7_vofs = (value << 8) | regs.m7_latch; regs.m7_vofs = (value << 8) | regs.m7_latch;
regs.m7_latch = value; regs.m7_latch = value;
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ppu1ofslatch); regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch);
regs.bg_ppu1ofslatch = value; regs.bg_ofslatch = value;
} }
//BG2HOFS //BG2HOFS
void PPU::mmio_w210f(uint8 value) { void PPU::mmio_w210f(uint8 value) {
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ppu1ofslatch & ~7) | (regs.bg_ppu2ofslatch & 7); regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG2] >> 8) & 7);
regs.bg_ppu1ofslatch = value; regs.bg_ofslatch = value;
regs.bg_ppu2ofslatch = value;
} }
//BG2VOFS //BG2VOFS
void PPU::mmio_w2110(uint8 value) { void PPU::mmio_w2110(uint8 value) {
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ppu1ofslatch); regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch);
regs.bg_ppu1ofslatch = value; regs.bg_ofslatch = value;
} }
//BG3HOFS //BG3HOFS
void PPU::mmio_w2111(uint8 value) { void PPU::mmio_w2111(uint8 value) {
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ppu1ofslatch & ~7) | (regs.bg_ppu2ofslatch & 7); regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG3] >> 8) & 7);
regs.bg_ppu1ofslatch = value; regs.bg_ofslatch = value;
regs.bg_ppu2ofslatch = value;
} }
//BG3VOFS //BG3VOFS
void PPU::mmio_w2112(uint8 value) { void PPU::mmio_w2112(uint8 value) {
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ppu1ofslatch); regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch);
regs.bg_ppu1ofslatch = value; regs.bg_ofslatch = value;
} }
//BG4HOFS //BG4HOFS
void PPU::mmio_w2113(uint8 value) { void PPU::mmio_w2113(uint8 value) {
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ppu1ofslatch & ~7) | (regs.bg_ppu2ofslatch & 7); regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG4] >> 8) & 7);
regs.bg_ppu1ofslatch = value; regs.bg_ofslatch = value;
regs.bg_ppu2ofslatch = value;
} }
//BG4VOFS //BG4VOFS
void PPU::mmio_w2114(uint8 value) { void PPU::mmio_w2114(uint8 value) {
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ppu1ofslatch); regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch);
regs.bg_ppu1ofslatch = value; regs.bg_ofslatch = value;
} }
//VMAIN //VMAIN

View file

@ -45,8 +45,7 @@ struct {
uint16 bg_tdaddr[4]; uint16 bg_tdaddr[4];
//$210d-$2114 //$210d-$2114
uint8 bg_ppu1ofslatch; uint8 bg_ofslatch;
uint8 bg_ppu2ofslatch;
uint16 m7_hofs, m7_vofs; uint16 m7_hofs, m7_vofs;
uint16 bg_hofs[4]; uint16 bg_hofs[4];
uint16 bg_vofs[4]; uint16 bg_vofs[4];

View file

@ -191,8 +191,7 @@ void PPU::power() {
regs.bg_tdaddr[BG4] = 0x0000; regs.bg_tdaddr[BG4] = 0x0000;
//$210d-$2114 //$210d-$2114
regs.bg_ppu1ofslatch = 0x00; regs.bg_ofslatch = 0x00;
regs.bg_ppu2ofslatch = 0x00;
regs.m7_hofs = regs.m7_vofs = 0x0000; regs.m7_hofs = regs.m7_vofs = 0x0000;
regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000; regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;
regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000; regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;

View file

@ -53,8 +53,7 @@ void PPU::serialize(serializer &s) {
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tdaddr[n]); for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tdaddr[n]);
s.integer(regs.bg_ppu1ofslatch); s.integer(regs.bg_ofslatch);
s.integer(regs.bg_ppu2ofslatch);
s.integer(regs.m7_hofs); s.integer(regs.m7_hofs);
s.integer(regs.m7_vofs); s.integer(regs.m7_vofs);
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_hofs[n]); for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_hofs[n]);

View file

@ -383,9 +383,8 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata; regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data; regs.mode7_latchdata = data;
bg1.regs.hoffset = (data << 8) | (regs.bgofs_ppu1latchdata & ~7) | (regs.bgofs_ppu2latchdata & 7); bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7);
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
regs.bgofs_ppu2latchdata = data;
return; return;
} }
@ -393,47 +392,44 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
regs.mode7_voffset = (data << 8) | regs.mode7_latchdata; regs.mode7_voffset = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data; regs.mode7_latchdata = data;
bg1.regs.voffset = (data << 8) | regs.bgofs_ppu1latchdata; bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
return; return;
} }
case 0x0f: { //BG2HOFS case 0x0f: { //BG2HOFS
bg2.regs.hoffset = (data << 8) | (regs.bgofs_ppu1latchdata & ~7) | (regs.bgofs_ppu2latchdata & 7); bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7);
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
regs.bgofs_ppu2latchdata = data;
return; return;
} }
case 0x10: { //BG2VOFS case 0x10: { //BG2VOFS
bg2.regs.voffset = (data << 8) | regs.bgofs_ppu1latchdata; bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
return; return;
} }
case 0x11: { //BG3HOFS case 0x11: { //BG3HOFS
bg3.regs.hoffset = (data << 8) | (regs.bgofs_ppu1latchdata & ~7) | (regs.bgofs_ppu2latchdata & 7); bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7);
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
regs.bgofs_ppu2latchdata = data; return;
return;
} }
case 0x12: { //BG3VOFS case 0x12: { //BG3VOFS
bg3.regs.voffset = (data << 8) | regs.bgofs_ppu1latchdata; bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
return; return;
} }
case 0x13: { //BG4HOFS case 0x13: { //BG4HOFS
bg4.regs.hoffset = (data << 8) | (regs.bgofs_ppu1latchdata & ~7) | (regs.bgofs_ppu2latchdata & 7); bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7);
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
regs.bgofs_ppu2latchdata = data; return;
return;
} }
case 0x14: { //BG4VOFS case 0x14: { //BG4VOFS
bg4.regs.voffset = (data << 8) | regs.bgofs_ppu1latchdata; bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
return; return;
} }
@ -692,8 +688,7 @@ void PPU::mmio_reset() {
regs.vram_readbuffer = 0; regs.vram_readbuffer = 0;
regs.oam_latchdata = 0; regs.oam_latchdata = 0;
regs.cgram_latchdata = 0; regs.cgram_latchdata = 0;
regs.bgofs_ppu1latchdata = 0; regs.bgofs_latchdata = 0;
regs.bgofs_ppu2latchdata = 0;
regs.mode7_latchdata = 0; regs.mode7_latchdata = 0;
regs.counters_latched = 0; regs.counters_latched = 0;

View file

@ -6,8 +6,7 @@ struct Regs {
uint16 vram_readbuffer; uint16 vram_readbuffer;
uint8 oam_latchdata; uint8 oam_latchdata;
uint8 cgram_latchdata; uint8 cgram_latchdata;
uint8 bgofs_ppu1latchdata; uint8 bgofs_latchdata;
uint8 bgofs_ppu2latchdata;
uint8 mode7_latchdata; uint8 mode7_latchdata;
bool counters_latched; bool counters_latched;

View file

@ -25,8 +25,7 @@ void PPU::serialize(serializer &s) {
s.integer(regs.vram_readbuffer); s.integer(regs.vram_readbuffer);
s.integer(regs.oam_latchdata); s.integer(regs.oam_latchdata);
s.integer(regs.cgram_latchdata); s.integer(regs.cgram_latchdata);
s.integer(regs.bgofs_ppu1latchdata); s.integer(regs.bgofs_latchdata);
s.integer(regs.bgofs_ppu2latchdata);
s.integer(regs.mode7_latchdata); s.integer(regs.mode7_latchdata);
s.integer(regs.counters_latched); s.integer(regs.counters_latched);

View file

@ -100,7 +100,6 @@ void NECDSP::exec_op(uint24 opcode) {
flag.s0 = (r & 0x8000); flag.s0 = (r & 0x8000);
flag.z = (r == 0); flag.z = (r == 0);
if (!flag.ov1) flag.s1 = flag.s0;
switch(alu) { switch(alu) {
case 1: case 2: case 3: case 10: case 13: case 14: case 15: { case 1: case 2: case 3: case 10: case 13: case 14: case 15: {
@ -112,14 +111,17 @@ void NECDSP::exec_op(uint24 opcode) {
case 4: case 5: case 6: case 7: case 8: case 9: { case 4: case 5: case 6: case 7: case 8: case 9: {
if(alu & 1) { if(alu & 1) {
//addition //addition
flag.ov0 = (q ^ r) & (p ^ r) & 0x8000; flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000;
flag.c = (r < q); flag.c = (r < q);
} else { } else {
//subtraction //subtraction
flag.ov0 = (q ^ r) & (q ^ p) & 0x8000; flag.ov0 = (q ^ r) & (q ^ p) & 0x8000;
flag.c = (r > q); flag.c = (r > q);
} }
flag.ov1 = (flag.ov0 & flag.ov1) ? (flag.s1 == flag.s0) : (flag.ov0 | flag.ov1); if(flag.ov0) {
flag.s1 = flag.ov1 ^ !(r & 0x8000);
flag.ov1 = !flag.ov1;
}
break; break;
} }
case 11: { case 11: {
@ -144,16 +146,15 @@ void NECDSP::exec_op(uint24 opcode) {
exec_ld((idb << 6) + dst); exec_ld((idb << 6) + dst);
if (dst != 4) { switch(dpl) {
switch(dpl) { case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC
case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC
case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR
case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR
}
regs.dp ^= dphm << 4;
} }
if(rpdcr && dst != 5) regs.rp--; regs.dp ^= dphm << 4;
if(rpdcr) regs.rp--;
} }
void NECDSP::exec_rt(uint24 opcode) { void NECDSP::exec_rt(uint24 opcode) {

View file

@ -337,7 +337,6 @@ void DSP::reset() {
#endif #endif
REG(flg) = 0xe0; REG(flg) = 0xe0;
REG(endx) = 0xff;
state.noise = 0x4000; state.noise = 0x4000;
state.echo_hist_pos = 0; state.echo_hist_pos = 0;

View file

@ -246,9 +246,8 @@ void PPU::mmio_w210d(uint8 data) {
regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata; regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data; regs.mode7_latchdata = data;
bg1.regs.hoffset = (data << 8) | (regs.bgofs_ppu1latchdata & ~7) | (regs.bgofs_ppu2latchdata); bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7);
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
regs.bgofs_ppu2latchdata = data;
} }
//BG1VOFS //BG1VOFS
@ -256,47 +255,44 @@ void PPU::mmio_w210e(uint8 data) {
regs.mode7_voffset = (data << 8) | regs.mode7_latchdata; regs.mode7_voffset = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data; regs.mode7_latchdata = data;
bg1.regs.voffset = (data << 8) | regs.bgofs_ppu1latchdata; bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
} }
//BG2HOFS //BG2HOFS
void PPU::mmio_w210f(uint8 data) { void PPU::mmio_w210f(uint8 data) {
bg2.regs.hoffset = (data << 8) | (regs.bgofs_ppu1latchdata & ~7) | (regs.bgofs_ppu2latchdata); bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7);
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
regs.bgofs_ppu2latchdata = data;
} }
//BG2VOFS //BG2VOFS
void PPU::mmio_w2110(uint8 data) { void PPU::mmio_w2110(uint8 data) {
bg2.regs.voffset = (data << 8) | regs.bgofs_ppu1latchdata; bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
} }
//BG3HOFS //BG3HOFS
void PPU::mmio_w2111(uint8 data) { void PPU::mmio_w2111(uint8 data) {
bg3.regs.hoffset = (data << 8) | (regs.bgofs_ppu1latchdata & ~7) | (regs.bgofs_ppu2latchdata); bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7);
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
regs.bgofs_ppu2latchdata = data;
} }
//BG3VOFS //BG3VOFS
void PPU::mmio_w2112(uint8 data) { void PPU::mmio_w2112(uint8 data) {
bg3.regs.voffset = (data << 8) | regs.bgofs_ppu1latchdata; bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
} }
//BG4HOFS //BG4HOFS
void PPU::mmio_w2113(uint8 data) { void PPU::mmio_w2113(uint8 data) {
bg4.regs.hoffset = (data << 8) | (regs.bgofs_ppu1latchdata & ~7) | (regs.bgofs_ppu2latchdata); bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7);
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
regs.bgofs_ppu2latchdata = data;
} }
//BG4VOFS //BG4VOFS
void PPU::mmio_w2114(uint8 data) { void PPU::mmio_w2114(uint8 data) {
bg4.regs.voffset = (data << 8) | regs.bgofs_ppu1latchdata; bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_ppu1latchdata = data; regs.bgofs_latchdata = data;
} }
//VMAIN //VMAIN
@ -694,8 +690,7 @@ void PPU::mmio_reset() {
regs.vram_readbuffer = 0x0000; regs.vram_readbuffer = 0x0000;
regs.oam_latchdata = 0x00; regs.oam_latchdata = 0x00;
regs.cgram_latchdata = 0x00; regs.cgram_latchdata = 0x00;
regs.bgofs_ppu1latchdata = 0x00; regs.bgofs_latchdata = 0x00;
regs.bgofs_ppu2latchdata = 0x00;
regs.mode7_latchdata = 0x00; regs.mode7_latchdata = 0x00;
regs.counters_latched = false; regs.counters_latched = false;
regs.latch_hcounter = 0; regs.latch_hcounter = 0;

View file

@ -5,8 +5,7 @@ struct {
uint16 vram_readbuffer; uint16 vram_readbuffer;
uint8 oam_latchdata; uint8 oam_latchdata;
uint8 cgram_latchdata; uint8 cgram_latchdata;
uint8 bgofs_ppu1latchdata; uint8 bgofs_latchdata;
uint3 bgofs_ppu2latchdata;
uint8 mode7_latchdata; uint8 mode7_latchdata;
bool counters_latched; bool counters_latched;
bool latch_hcounter; bool latch_hcounter;

View file

@ -18,8 +18,7 @@ void PPU::serialize(serializer &s) {
s.integer(regs.vram_readbuffer); s.integer(regs.vram_readbuffer);
s.integer(regs.oam_latchdata); s.integer(regs.oam_latchdata);
s.integer(regs.cgram_latchdata); s.integer(regs.cgram_latchdata);
s.integer(regs.bgofs_ppu1latchdata); s.integer(regs.bgofs_latchdata);
s.integer(regs.bgofs_ppu2latchdata);
s.integer(regs.mode7_latchdata); s.integer(regs.mode7_latchdata);
s.integer(regs.counters_latched); s.integer(regs.counters_latched);
s.integer(regs.latch_hcounter); s.integer(regs.latch_hcounter);

View file

@ -80,12 +80,14 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
if(regs.p.p) break; //writes only valid when P flag is clear if(regs.p.p) break; //writes only valid when P flag is clear
status.clock_speed = (data >> 6) & 3; status.clock_speed = (data >> 6) & 3;
status.ram_speed = (data >> 4) & 3; status.timer_speed = (data >> 4) & 3;
status.timers_enabled = data & 0x08; status.timers_enabled = data & 0x08;
status.ram_disabled = data & 0x04; status.ram_disabled = data & 0x04;
status.ram_writable = data & 0x02; status.ram_writable = data & 0x02;
status.timers_disabled = data & 0x01; status.timers_disabled = data & 0x01;
status.timer_step = (1 << status.clock_speed) + (2 << status.timer_speed);
t0.sync_stage1(); t0.sync_stage1();
t1.sync_stage1(); t1.sync_stage1();
t2.sync_stage1(); t2.sync_stage1();
@ -174,29 +176,23 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
ram_write(addr, data); ram_write(addr, data);
} }
unsigned SMP::speed(uint16 addr) const {
if((addr & 0xfff0) == 0x00f0) return status.clock_speed;
if(addr >= 0xffc0 && status.iplrom_enabled) return status.clock_speed;
return status.ram_speed;
}
void SMP::op_io() { void SMP::op_io() {
add_clocks(24); add_clocks(24);
cycle_edge(status.clock_speed); cycle_edge();
} }
uint8 SMP::op_read(uint16 addr) { uint8 SMP::op_read(uint16 addr) {
add_clocks(12); add_clocks(12);
uint8 r = op_busread(addr); uint8 r = op_busread(addr);
add_clocks(12); add_clocks(12);
cycle_edge(speed(addr)); cycle_edge();
return r; return r;
} }
void SMP::op_write(uint16 addr, uint8 data) { void SMP::op_write(uint16 addr, uint8 data) {
add_clocks(24); add_clocks(24);
op_buswrite(addr, data); op_buswrite(addr, data);
cycle_edge(speed(addr)); cycle_edge();
} }
#endif #endif

View file

@ -4,8 +4,6 @@ void ram_write(uint16 addr, uint8 data);
uint8 op_busread(uint16 addr); uint8 op_busread(uint16 addr);
void op_buswrite(uint16 addr, uint8 data); void op_buswrite(uint16 addr, uint8 data);
alwaysinline unsigned speed(uint16 addr) const;
void op_io(); void op_io();
debugvirtual uint8 op_read(uint16 addr); debugvirtual uint8 op_read(uint16 addr);
debugvirtual void op_write(uint16 addr, uint8 data); debugvirtual void op_write(uint16 addr, uint8 data);

View file

@ -4,8 +4,12 @@ void SMP::serialize(serializer &s) {
Processor::serialize(s); Processor::serialize(s);
SMPcore::core_serialize(s); SMPcore::core_serialize(s);
s.integer(status.clock_counter);
s.integer(status.dsp_counter);
s.integer(status.timer_step);
s.integer(status.clock_speed); s.integer(status.clock_speed);
s.integer(status.ram_speed); s.integer(status.timer_speed);
s.integer(status.timers_enabled); s.integer(status.timers_enabled);
s.integer(status.ram_disabled); s.integer(status.ram_disabled);
s.integer(status.ram_writable); s.integer(status.ram_writable);

View file

@ -76,9 +76,13 @@ void SMP::reset() {
memory::apuram.write(i, 0x00); memory::apuram.write(i, 0x00);
} }
status.clock_counter = 0;
status.dsp_counter = 0;
status.timer_step = 3;
//$00f0 //$00f0
status.clock_speed = 0; status.clock_speed = 0;
status.ram_speed = 0; status.timer_speed = 0;
status.timers_enabled = true; status.timers_enabled = true;
status.ram_disabled = false; status.ram_disabled = false;
status.ram_writable = true; status.ram_writable = true;

View file

@ -21,9 +21,14 @@ private:
#include "timing/timing.hpp" #include "timing/timing.hpp"
struct { struct {
//timing
unsigned clock_counter;
unsigned dsp_counter;
unsigned timer_step;
//$00f0 //$00f0
uint8 clock_speed; uint8 clock_speed;
uint8 ram_speed; uint8 timer_speed;
bool timers_enabled; bool timers_enabled;
bool ram_disabled; bool ram_disabled;
bool ram_writable; bool ram_writable;

View file

@ -9,22 +9,25 @@ void SMP::add_clocks(unsigned clocks) {
if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu(); if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu();
} }
void SMP::cycle_edge(unsigned speed) { void SMP::cycle_edge() {
static const uint8 wait_states[] = {0, 24*1, 24*4, 24*9}; t0.tick();
t1.tick();
unsigned ticks = 1 << speed; t2.tick();
t0.tick(ticks);
t1.tick(ticks);
t2.tick(ticks);
//TEST register S-SMP speed control
//24 clocks have already been added for this cycle at this point //24 clocks have already been added for this cycle at this point
if(speed) add_clocks(wait_states[speed]); 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
}
} }
template<unsigned timer_frequency> template<unsigned timer_frequency>
void SMP::sSMPTimer<timer_frequency>::tick(unsigned step) { void SMP::sSMPTimer<timer_frequency>::tick() {
//stage 0 increment //stage 0 increment
stage0_ticks += step; stage0_ticks += smp.status.timer_step;
if(stage0_ticks < timer_frequency) return; if(stage0_ticks < timer_frequency) return;
stage0_ticks -= timer_frequency; stage0_ticks -= timer_frequency;

View file

@ -9,13 +9,13 @@ public:
bool enabled; bool enabled;
uint8 target; uint8 target;
void tick(unsigned step); void tick();
void sync_stage1(); void sync_stage1();
}; };
sSMPTimer<64> t0; sSMPTimer<192> t0;
sSMPTimer<64> t1; sSMPTimer<192> t1;
sSMPTimer< 8> t2; sSMPTimer< 24> t2;
alwaysinline void add_clocks(unsigned clocks); alwaysinline void add_clocks(unsigned clocks);
alwaysinline void cycle_edge(unsigned speed); alwaysinline void cycle_edge();

View file

@ -3,7 +3,7 @@ namespace SNES {
static const char Name[] = "bsnes-classic"; static const char Name[] = "bsnes-classic";
static const char Version[] = "073u1"; static const char Version[] = "073u1";
static const unsigned SerializerSignature = 0x43545342; //'BSTC' static const unsigned SerializerSignature = 0x43545342; //'BSTC'
static const unsigned SerializerVersion = 7; static const unsigned SerializerVersion = 6;
} }
} }

View file

@ -11,7 +11,7 @@ link :=
ifeq ($(DEBUG), 1) ifeq ($(DEBUG), 1)
flags += -O0 -g -DDEBUG flags += -O0 -g -DDEBUG
else else
flags += -O3 -fomit-frame-pointer -DNDEBUG flags += -O3 -fomit-frame-pointer -DNDEBUG -march=native
endif endif
# silence warnings # silence warnings

View file

@ -11,7 +11,7 @@
namespace nall { namespace nall {
struct Keyboard; struct Keyboard;
Keyboard keyboard(unsigned = 0); Keyboard& keyboard(unsigned = 0);
static const char KeyboardScancodeName[][64] = { static const char KeyboardScancodeName[][64] = {
"Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
@ -122,9 +122,12 @@ struct Keyboard {
Keyboard(unsigned ID_) : ID(ID_) {} Keyboard(unsigned ID_) : ID(ID_) {}
}; };
inline Keyboard keyboard(unsigned id) { inline Keyboard& keyboard(unsigned id) {
assert(id < Keyboard::Count); static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
return Keyboard(id); switch(id) { default:
case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
}
} }
static const char MouseScancodeName[][64] = { static const char MouseScancodeName[][64] = {
@ -133,7 +136,7 @@ static const char MouseScancodeName[][64] = {
}; };
struct Mouse; struct Mouse;
Mouse mouse(unsigned = 0); Mouse& mouse(unsigned = 0);
struct Mouse { struct Mouse {
const unsigned ID; const unsigned ID;
@ -217,9 +220,12 @@ struct Mouse {
Mouse(unsigned ID_) : ID(ID_) {} Mouse(unsigned ID_) : ID(ID_) {}
}; };
inline Mouse mouse(unsigned id) { inline Mouse& mouse(unsigned id) {
assert(id < Mouse::Count); static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
return Mouse(id); switch(id) { default:
case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
}
} }
static const char JoypadScancodeName[][64] = { static const char JoypadScancodeName[][64] = {
@ -233,7 +239,7 @@ static const char JoypadScancodeName[][64] = {
}; };
struct Joypad; struct Joypad;
Joypad joypad(unsigned = 0); Joypad& joypad(unsigned = 0);
struct Joypad { struct Joypad {
const unsigned ID; const unsigned ID;
@ -339,9 +345,12 @@ struct Joypad {
Joypad(unsigned ID_) : ID(ID_) {} Joypad(unsigned ID_) : ID(ID_) {}
}; };
inline Joypad joypad(unsigned id) { inline Joypad& joypad(unsigned id) {
assert(id < Joypad::Count); static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
return Joypad(id); switch(id) { default:
case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
}
} }
struct Scancode { struct Scancode {

View file

@ -11,7 +11,7 @@
namespace nall { namespace nall {
struct Keyboard; struct Keyboard;
Keyboard keyboard(unsigned = 0); Keyboard& keyboard(unsigned = 0);
static const char KeyboardScancodeName[][64] = { static const char KeyboardScancodeName[][64] = {
"Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
@ -122,9 +122,12 @@ struct Keyboard {
Keyboard(unsigned ID_) : ID(ID_) {} Keyboard(unsigned ID_) : ID(ID_) {}
}; };
inline Keyboard keyboard(unsigned id) { inline Keyboard& keyboard(unsigned id) {
assert(id < Keyboard::Count); static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
return Keyboard(id); switch(id) { default:
case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
}
} }
static const char MouseScancodeName[][64] = { static const char MouseScancodeName[][64] = {
@ -133,7 +136,7 @@ static const char MouseScancodeName[][64] = {
}; };
struct Mouse; struct Mouse;
Mouse mouse(unsigned = 0); Mouse& mouse(unsigned = 0);
struct Mouse { struct Mouse {
const unsigned ID; const unsigned ID;
@ -217,9 +220,12 @@ struct Mouse {
Mouse(unsigned ID_) : ID(ID_) {} Mouse(unsigned ID_) : ID(ID_) {}
}; };
inline Mouse mouse(unsigned id) { inline Mouse& mouse(unsigned id) {
assert(id < Mouse::Count); static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
return Mouse(id); switch(id) { default:
case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
}
} }
static const char JoypadScancodeName[][64] = { static const char JoypadScancodeName[][64] = {
@ -233,7 +239,7 @@ static const char JoypadScancodeName[][64] = {
}; };
struct Joypad; struct Joypad;
Joypad joypad(unsigned = 0); Joypad& joypad(unsigned = 0);
struct Joypad { struct Joypad {
const unsigned ID; const unsigned ID;
@ -339,9 +345,12 @@ struct Joypad {
Joypad(unsigned ID_) : ID(ID_) {} Joypad(unsigned ID_) : ID(ID_) {}
}; };
inline Joypad joypad(unsigned id) { inline Joypad& joypad(unsigned id) {
assert(id < Joypad::Count); static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
return Joypad(id); switch(id) { default:
case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
}
} }
struct Scancode { struct Scancode {

View file

@ -11,7 +11,7 @@
namespace nall { namespace nall {
struct Keyboard; struct Keyboard;
Keyboard keyboard(unsigned = 0); Keyboard& keyboard(unsigned = 0);
static const char KeyboardScancodeName[][64] = { static const char KeyboardScancodeName[][64] = {
"Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
@ -122,9 +122,12 @@ struct Keyboard {
Keyboard(unsigned ID_) : ID(ID_) {} Keyboard(unsigned ID_) : ID(ID_) {}
}; };
inline Keyboard keyboard(unsigned id) { inline Keyboard& keyboard(unsigned id) {
assert(id < Keyboard::Count); static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
return Keyboard(id); switch(id) { default:
case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
}
} }
static const char MouseScancodeName[][64] = { static const char MouseScancodeName[][64] = {
@ -133,7 +136,7 @@ static const char MouseScancodeName[][64] = {
}; };
struct Mouse; struct Mouse;
Mouse mouse(unsigned = 0); Mouse& mouse(unsigned = 0);
struct Mouse { struct Mouse {
const unsigned ID; const unsigned ID;
@ -217,9 +220,12 @@ struct Mouse {
Mouse(unsigned ID_) : ID(ID_) {} Mouse(unsigned ID_) : ID(ID_) {}
}; };
inline Mouse mouse(unsigned id) { inline Mouse& mouse(unsigned id) {
assert(id < Mouse::Count); static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
return Mouse(id); switch(id) { default:
case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
}
} }
static const char JoypadScancodeName[][64] = { static const char JoypadScancodeName[][64] = {
@ -233,7 +239,7 @@ static const char JoypadScancodeName[][64] = {
}; };
struct Joypad; struct Joypad;
Joypad joypad(unsigned = 0); Joypad& joypad(unsigned = 0);
struct Joypad { struct Joypad {
const unsigned ID; const unsigned ID;
@ -339,9 +345,12 @@ struct Joypad {
Joypad(unsigned ID_) : ID(ID_) {} Joypad(unsigned ID_) : ID(ID_) {}
}; };
inline Joypad joypad(unsigned id) { inline Joypad& joypad(unsigned id) {
assert(id < Joypad::Count); static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
return Joypad(id); switch(id) { default:
case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
}
} }
struct Scancode { struct Scancode {