mirror of https://github.com/bsnes-emu/bsnes.git
Updated to v067r23 release.
byuu says: Added missing $4200 IRQ lock, which fixes Chou Aniki on the fast CPU core, so slower PCs can get their brotherly love on. Added range-based controller IOBit latching to the fast CPU core, which enables Super Scope and Justifier support. Uses the priority queue as well, so there is zero speed-hit. Given the way range-testing works, the trigger point may vary by 1-2 pixels when firing at the same spot. Not really a big deal when it avoids a massive speed penalty. Fixed PAL and interlace-mode HVIRQs at V=0,H<2 on the fast CPU core. Added the dot-renderer's sprite list update-on-OAM-write functionality to the scanline-based PPU renderer. Unfortunately it looks like all the speed gain was already taken from the global dirty flag I was using before, but this certainly won't hurt speed any, so whatever. Added #ifdef to stop CoInitialize(0) on non-Windows ports. Added #ifdefs to stop gradient fade on Windows port. Not going to fuck over the Linux port aesthetic because of Qt bug #47,326,927. If there's a way to tell what Qt theme is being used, I can leave it enabled for XP/Vista themes. Moved HDMA trigger from 1104 to 1112, and reduced channel overhead from 24 to 16, to better simulate one-cycle DMA->CPU sync. Code clarity: I've re-added my varint.hpp classes, and am actively using them in the accuracy cores. So far, I haven't done anything that would detriment speed, but it is certainly cool. The APU ports exposed by the CPU and SMP now take uint2 address arguments, the CPU WRAM address register is a uint17, and the IRQ H/VTIME values are uint10. This basically allows the source to clearly convey the data sizes, and eliminates the need to manually mask values when writing to registers or reading from memory. I'm going to be doing this everywhere, and it will have a speed impact eventually, because the automation means we can't skip masks when we know the data is already masked off. Source: archive contains the launcher code, so that I can look into why it's crashing on XP tomorrow. It doesn't look like Circuit USA's flags are going to work too well with this new CPU core. Still not sure what the hell Robocop vs The Terminator is doing, I'll read through the mega SNES thread for clues tomorrow. Speedy Gonzales is definitely broken, as modifying the MDR was breaking things with my current core. Probably because the new CPU core doesn't wait for a cycle edge to trigger. I was thinking that perhaps we could keep some form of cheat codes list to work as game-specific hacks for the performance core. Keeps the hacks out of the emulator, but could allow the remaining bugs to be worked around for people who have no choice but to use the performance core.
This commit is contained in:
parent
cda10094da
commit
70429285ba
8
Makefile
8
Makefile
|
@ -1,6 +1,6 @@
|
|||
include nall/Makefile
|
||||
snes := snes
|
||||
profile := accuracy
|
||||
profile := performance
|
||||
ui := qt
|
||||
|
||||
# compiler
|
||||
|
@ -53,8 +53,8 @@ objects := $(patsubst %,obj/%.o,$(objects))
|
|||
# targets
|
||||
build: ui_build $(objects)
|
||||
ifeq ($(platform),osx)
|
||||
test -d ../bsnes.app || mkdir -p ../bsnes.app/Contents/MacOS
|
||||
$(strip $(cpp) -o ../bsnes.app/Contents/MacOS/bsnes $(objects) $(link))
|
||||
test -d ../bsnes-$(profile).app || mkdir -p ../bsnes-$(profile).app/Contents/MacOS
|
||||
$(strip $(cpp) -o ../bsnes-$(profile).app/Contents/MacOS/bsnes-$(profile) $(objects) $(link))
|
||||
else
|
||||
$(strip $(cpp) -o out/bsnes-$(profile) $(objects) $(link))
|
||||
endif
|
||||
|
@ -87,6 +87,6 @@ clean: ui_clean
|
|||
-@$(call delete,*.manifest)
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes-`date +%Y%m%d`.tar.bz2 libco nall obj out qt ruby snes Makefile sync.sh
|
||||
tar -cjf bsnes-`date +%Y%m%d`.tar.bz2 launcher libco nall obj out qt ruby snes Makefile sync.sh cc.bat clean.bat
|
||||
|
||||
help:;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="bsnes" version="1.0.0.0" processorArchitecture="x86"/>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,4 @@
|
|||
@windres resource.rc resource.o
|
||||
@mingw32-g++ -std=gnu++0x -mwindows -s -O3 -fomit-frame-pointer -I.. -o ../out/bsnes launcher.cpp resource.o
|
||||
@del *.o
|
||||
@pause
|
|
@ -0,0 +1,2 @@
|
|||
clear
|
||||
g++ -std=gnu++0x -s -O3 -fomit-frame-pointer -I.. -o ../out/bsnes launcher.cpp
|
|
@ -0,0 +1,89 @@
|
|||
#include <nall/config.hpp>
|
||||
#include <nall/detect.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
|
||||
char* userpath(char *path) {
|
||||
*path = 0;
|
||||
struct passwd *userinfo = getpwuid(getuid());
|
||||
if(userinfo) strcpy(path, userinfo->pw_dir);
|
||||
return path;
|
||||
}
|
||||
|
||||
char *getcwd(char *path) {
|
||||
return getcwd(path, PATH_MAX);
|
||||
}
|
||||
#elif defined(PLATFORM_WIN)
|
||||
#include <nall/utf8.hpp>
|
||||
#include <process.h>
|
||||
#include <wchar.h>
|
||||
#include <windows.h>
|
||||
|
||||
char* realpath(const char *filename, char *resolvedname) {
|
||||
wchar_t fn[_MAX_PATH] = L"";
|
||||
_wfullpath(fn, nall::utf16_t(filename), _MAX_PATH);
|
||||
strcpy(resolvedname, nall::utf8_t(fn));
|
||||
return resolvedname;
|
||||
}
|
||||
|
||||
char* userpath(char *path) {
|
||||
wchar_t fp[_MAX_PATH] = L"";
|
||||
SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp);
|
||||
strcpy(path, nall::utf8_t(fp));
|
||||
return path;
|
||||
}
|
||||
|
||||
char* getcwd(char *path) {
|
||||
wchar_t fp[_MAX_PATH] = L"";
|
||||
_wgetcwd(fp, _MAX_PATH);
|
||||
strcpy(path, nall::utf8_t(fp));
|
||||
return path;
|
||||
}
|
||||
|
||||
intptr_t execv(const char *cmdname, const char *const *argv) {
|
||||
int argc = __argc;
|
||||
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
return _wexecv(nall::utf16_t(cmdname), wargv);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char path[PATH_MAX], *unused;
|
||||
unused = realpath(argv[0], path);
|
||||
string realPath = dir(path);
|
||||
string basePath = string(dir(path), "bsnes.cfg");
|
||||
unused = userpath(path);
|
||||
if(!strend(path, "/") && !strend(path, "\\")) strcat(path, "/");
|
||||
string userPath = string(path, ".bsnes/bsnes.cfg");
|
||||
|
||||
configuration config;
|
||||
string profile;
|
||||
config.attach(profile = "", "system.profile");
|
||||
if(config.load(userPath) == false) config.load(basePath);
|
||||
if(profile == "") profile = "compatibility";
|
||||
|
||||
string binaryName = string("bsnes-", profile);
|
||||
#if defined(PLATFORM_WIN)
|
||||
binaryName << ".dll";
|
||||
#endif
|
||||
|
||||
string fileName = string("/usr/local/bin/", binaryName);
|
||||
if(!file::exists(fileName)) fileName = string("/usr/bin/", binaryName);
|
||||
if(!file::exists(fileName)) fileName = string(realPath, binaryName);
|
||||
if(!file::exists(fileName)) {
|
||||
#if defined(PLATFORM_WIN)
|
||||
MessageBox(0, string("Error: unable to locate binary file :", binaryName), "bsnes", MB_OK);
|
||||
#else
|
||||
print("[bsnes] Error: unable to locate binary file: ", binaryName, "\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
execv(fileName, argv);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
1 24 "bsnes.Manifest"
|
||||
IDI_ICON1 ICON DISCARDABLE "bsnes.ico"
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef NALL_VARINT_HPP
|
||||
#define NALL_VARINT_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <nall/bit.hpp>
|
||||
#include <nall/static.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
|
||||
namespace nall {
|
||||
template<unsigned bits> class uint_t {
|
||||
|
@ -22,7 +22,7 @@ namespace nall {
|
|||
>::type
|
||||
>::type
|
||||
>::type T;
|
||||
static_assert<!is_void<T>::value> uint_assert;
|
||||
static_assert(!std::is_same<T, void>::value, "");
|
||||
T data;
|
||||
|
||||
public:
|
||||
|
@ -63,7 +63,7 @@ namespace nall {
|
|||
>::type
|
||||
>::type
|
||||
>::type T;
|
||||
static_assert<!is_void<T>::value> int_assert;
|
||||
static_assert(!std::is_same<T, void>::value, "");
|
||||
T data;
|
||||
|
||||
public:
|
||||
|
|
|
@ -61,12 +61,12 @@ void Application::locateFile(string &filename, bool createDataDirectory) {
|
|||
}
|
||||
|
||||
int Application::main(int &argc, char **argv) {
|
||||
CoInitialize(0);
|
||||
|
||||
app = new App(argc, argv);
|
||||
#if !defined(PLATFORM_WIN)
|
||||
//Windows port uses 256x256 icon from resource file
|
||||
app->setWindowIcon(QIcon(":/bsnes.png"));
|
||||
#else
|
||||
//Windows port uses 256x256 icon from resource file
|
||||
CoInitialize(0);
|
||||
#endif
|
||||
|
||||
initargs(argc, argv); //ensure argv[]s are in UTF-8 format
|
||||
|
|
|
@ -20,7 +20,9 @@ ProfileSettingsWindow::ProfileSettingsWindow() {
|
|||
profileAccuracy->setStyleSheet(
|
||||
"font-weight: bold;"
|
||||
"font-size: 12pt;"
|
||||
#if !defined(PLATFORM_WIN)
|
||||
"background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 rgba(255, 0, 0, 48), stop: 1 rgba(255, 0, 0, 0));"
|
||||
#endif
|
||||
);
|
||||
layout->addWidget(profileAccuracy);
|
||||
|
||||
|
@ -37,7 +39,9 @@ ProfileSettingsWindow::ProfileSettingsWindow() {
|
|||
profileCompatibility->setStyleSheet(
|
||||
"font-weight: bold;"
|
||||
"font-size: 12pt;"
|
||||
#if !defined(PLATFORM_WIN)
|
||||
"background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 rgba(0, 0, 255, 48), stop: 1 rgba(0, 0, 255, 0));"
|
||||
#endif
|
||||
);
|
||||
layout->addWidget(profileCompatibility);
|
||||
|
||||
|
@ -54,12 +58,14 @@ ProfileSettingsWindow::ProfileSettingsWindow() {
|
|||
profilePerformance->setStyleSheet(
|
||||
"font-weight: bold;"
|
||||
"font-size: 12pt;"
|
||||
#if !defined(PLATFORM_WIN)
|
||||
"background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 rgba(0, 255, 0, 48), stop: 1 rgba(0, 255, 0, 0));"
|
||||
#endif
|
||||
);
|
||||
layout->addWidget(profilePerformance);
|
||||
|
||||
profilePerformanceInfo = new QLabel(
|
||||
"<b>System Requirements:</b> Intel Atom, Intel Pentium IV or AMD Athlon processor.<br>"
|
||||
"<b>System Requirements:</b> Intel Pentium IV or AMD Athlon processor.<br>"
|
||||
"High accuracy with reasonable compromises for performance.<br>"
|
||||
"Sacrifices a small degree of compatibility to run full-speed on older hardware.<br>"
|
||||
"Use this mode for slower systems, or if you are running on battery power."
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
@g++ -std=gnu++0x -O3 -fomit-frame-pointer -I../.. -o test test.cpp -DAUDIO_DIRECTSOUND -DAUDIO_XAUDIO2 -DINPUT_DIRECTINPUT -lole32 -luuid -ldxguid -ldsound -ldinput8
|
||||
@pause
|
|
@ -1,40 +0,0 @@
|
|||
#include <nall/foreach.hpp>
|
||||
#include <nall/string.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <ruby/ruby.cpp>
|
||||
using namespace ruby;
|
||||
|
||||
#include <conio.h>
|
||||
|
||||
int main() {
|
||||
CoInitialize(0);
|
||||
|
||||
audio.driver("XAudio2");
|
||||
audio.set(Audio::Handle, (uintptr_t)GetDesktopWindow());
|
||||
audio.set(Audio::Synchronize, true);
|
||||
audio.set(Audio::Frequency, 44100U);
|
||||
if(audio.init() == false) {
|
||||
printf("Failed to initialize audio driver.\n");
|
||||
getch();
|
||||
return 0;
|
||||
}
|
||||
|
||||
input.driver("DirectInput");
|
||||
input.set(Input::Handle, (uintptr_t)GetDesktopWindow());
|
||||
if(input.init() == false) {
|
||||
printf("Failed to initialize input driver.\n");
|
||||
getch();
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(true) {
|
||||
int16_t table[Scancode::Limit];
|
||||
input.poll(table);
|
||||
for(unsigned i = 0; i < Scancode::Limit; i++) {
|
||||
//if(table[i]) printf("%.4x\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
|
@ -132,11 +132,6 @@ void CPU::reset() {
|
|||
mmio_reset();
|
||||
dma_reset();
|
||||
timing_reset();
|
||||
|
||||
apu_port[0] = 0x00;
|
||||
apu_port[1] = 0x00;
|
||||
apu_port[2] = 0x00;
|
||||
apu_port[3] = 0x00;
|
||||
}
|
||||
|
||||
CPU::CPU() {
|
||||
|
|
|
@ -7,11 +7,12 @@ public:
|
|||
void synchronize_ppu();
|
||||
void synchronize_coprocessor();
|
||||
|
||||
uint8 port_read(uint2 port) const;
|
||||
void port_write(uint2 port, uint8 data);
|
||||
|
||||
uint8 pio();
|
||||
bool joylatch();
|
||||
alwaysinline bool interrupt_pending() { return status.interrupt_pending; }
|
||||
alwaysinline uint8 port_read(uint8 port) { return apu_port[port & 3]; }
|
||||
alwaysinline void port_write(uint8 port, uint8 data) { apu_port[port & 3] = data; }
|
||||
|
||||
void enter();
|
||||
void power();
|
||||
|
@ -71,8 +72,11 @@ private:
|
|||
bool hdma_mode; //0 = init, 1 = run
|
||||
|
||||
//MMIO
|
||||
//$2140-217f
|
||||
uint8 port[4];
|
||||
|
||||
//$2181-$2183
|
||||
uint32 wram_addr;
|
||||
uint17 wram_addr;
|
||||
|
||||
//$4016-$4017
|
||||
bool joypad_strobe_latch;
|
||||
|
@ -93,10 +97,11 @@ private:
|
|||
|
||||
//$4204-$4206
|
||||
uint16 wrdiva;
|
||||
uint8 wrdivb;
|
||||
uint8 wrdivb;
|
||||
|
||||
//$4207-$420a
|
||||
uint16 hirq_pos, virq_pos;
|
||||
uint10 hirq_pos;
|
||||
uint10 virq_pos;
|
||||
|
||||
//$420d
|
||||
unsigned rom_speed;
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
void CPU::dma_add_clocks(unsigned clocks) {
|
||||
status.dma_clocks += clocks;
|
||||
add_clocks(clocks);
|
||||
synchronize_ppu();
|
||||
synchronize_coprocessor();
|
||||
}
|
||||
|
||||
//=============
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
uint8 CPU::port_read(uint2 port) const { return status.port[port]; }
|
||||
void CPU::port_write(uint2 port, uint8 data) { status.port[port] = data; }
|
||||
|
||||
void CPU::op_io() {
|
||||
status.clock_count = 6;
|
||||
dma_edge();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
uint8 apu_port[4];
|
||||
|
||||
void op_io();
|
||||
debugvirtual uint8 op_read(uint32 addr);
|
||||
debugvirtual void op_write(uint32 addr, uint8 data);
|
||||
|
|
|
@ -5,33 +5,27 @@ bool CPU::joylatch() { return status.joypad_strobe_latch; }
|
|||
|
||||
//WMDATA
|
||||
uint8 CPU::mmio_r2180() {
|
||||
uint8 r = bus.read(0x7e0000 | status.wram_addr);
|
||||
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||
return r;
|
||||
return bus.read(0x7e0000 | status.wram_addr++);
|
||||
}
|
||||
|
||||
//WMDATA
|
||||
void CPU::mmio_w2180(uint8 data) {
|
||||
bus.write(0x7e0000 | status.wram_addr, data);
|
||||
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||
bus.write(0x7e0000 | status.wram_addr++, data);
|
||||
}
|
||||
|
||||
//WMADDL
|
||||
void CPU::mmio_w2181(uint8 data) {
|
||||
status.wram_addr = (status.wram_addr & 0xffff00) | (data);
|
||||
status.wram_addr &= 0x01ffff;
|
||||
status.wram_addr = (status.wram_addr & 0x01ff00) | (data << 0);
|
||||
}
|
||||
|
||||
//WMADDM
|
||||
void CPU::mmio_w2182(uint8 data) {
|
||||
status.wram_addr = (status.wram_addr & 0xff00ff) | (data << 8);
|
||||
status.wram_addr &= 0x01ffff;
|
||||
status.wram_addr = (status.wram_addr & 0x0100ff) | (data << 8);
|
||||
}
|
||||
|
||||
//WMADDH
|
||||
void CPU::mmio_w2183(uint8 data) {
|
||||
status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16);
|
||||
status.wram_addr &= 0x01ffff;
|
||||
status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16);
|
||||
}
|
||||
|
||||
//JOYSER0
|
||||
|
@ -42,10 +36,7 @@ void CPU::mmio_w4016(uint8 data) {
|
|||
bool old_latch = status.joypad_strobe_latch;
|
||||
bool new_latch = data & 1;
|
||||
status.joypad_strobe_latch = new_latch;
|
||||
|
||||
if(old_latch != new_latch) {
|
||||
input.poll();
|
||||
}
|
||||
if(old_latch != new_latch) input.poll();
|
||||
}
|
||||
|
||||
//JOYSER0
|
||||
|
@ -69,15 +60,13 @@ uint8 CPU::mmio_r4017() {
|
|||
|
||||
//NMITIMEN
|
||||
void CPU::mmio_w4200(uint8 data) {
|
||||
status.auto_joypad_poll = !!(data & 0x01);
|
||||
status.auto_joypad_poll = data & 1;
|
||||
nmitimen_update(data);
|
||||
}
|
||||
|
||||
//WRIO
|
||||
void CPU::mmio_w4201(uint8 data) {
|
||||
if((status.pio & 0x80) && !(data & 0x80)) {
|
||||
ppu.latch_counters();
|
||||
}
|
||||
if((status.pio & 0x80) && !(data & 0x80)) ppu.latch_counters();
|
||||
status.pio = data;
|
||||
}
|
||||
|
||||
|
@ -100,7 +89,7 @@ void CPU::mmio_w4203(uint8 data) {
|
|||
|
||||
//WRDIVL
|
||||
void CPU::mmio_w4204(uint8 data) {
|
||||
status.wrdiva = (status.wrdiva & 0xff00) | (data);
|
||||
status.wrdiva = (status.wrdiva & 0xff00) | (data << 0);
|
||||
}
|
||||
|
||||
//WRDIVH
|
||||
|
@ -121,26 +110,22 @@ void CPU::mmio_w4206(uint8 data) {
|
|||
|
||||
//HTIMEL
|
||||
void CPU::mmio_w4207(uint8 data) {
|
||||
status.hirq_pos = (status.hirq_pos & ~0xff) | (data);
|
||||
status.hirq_pos &= 0x01ff;
|
||||
status.hirq_pos = (status.hirq_pos & 0x0100) | (data << 0);
|
||||
}
|
||||
|
||||
//HTIMEH
|
||||
void CPU::mmio_w4208(uint8 data) {
|
||||
status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8);
|
||||
status.hirq_pos &= 0x01ff;
|
||||
status.hirq_pos = (status.hirq_pos & 0x00ff) | (data << 8);
|
||||
}
|
||||
|
||||
//VTIMEL
|
||||
void CPU::mmio_w4209(uint8 data) {
|
||||
status.virq_pos = (status.virq_pos & ~0xff) | (data);
|
||||
status.virq_pos &= 0x01ff;
|
||||
status.virq_pos = (status.virq_pos & 0x0100) | (data << 0);
|
||||
}
|
||||
|
||||
//VTIMEH
|
||||
void CPU::mmio_w420a(uint8 data) {
|
||||
status.virq_pos = (status.virq_pos & 0xff) | (data << 8);
|
||||
status.virq_pos &= 0x01ff;
|
||||
status.virq_pos = (status.virq_pos & 0x00ff) | (data << 8);
|
||||
}
|
||||
|
||||
//DMAEN
|
||||
|
@ -191,16 +176,9 @@ uint8 CPU::mmio_r4211() {
|
|||
uint8 CPU::mmio_r4212() {
|
||||
uint8 r = (regs.mdr & 0x3e);
|
||||
uint16 vs = ppu.overscan() == false ? 225 : 240;
|
||||
|
||||
//auto joypad polling
|
||||
if(vcounter() >= vs && vcounter() <= (vs + 2))r |= 0x01;
|
||||
|
||||
//hblank
|
||||
if(hcounter() <= 2 || hcounter() >= 1096)r |= 0x40;
|
||||
|
||||
//vblank
|
||||
if(vcounter() >= vs)r |= 0x80;
|
||||
|
||||
if(vcounter() >= vs && vcounter() <= (vs + 2)) r |= 0x01; //auto joypad polling
|
||||
if(hcounter() <= 2 || hcounter() >= 1096) r |= 0x40; //hblank
|
||||
if(vcounter() >= vs) r |= 0x80; //vblank
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -211,7 +189,7 @@ uint8 CPU::mmio_r4213() {
|
|||
|
||||
//RDDIVL
|
||||
uint8 CPU::mmio_r4214() {
|
||||
return status.rddiv;
|
||||
return status.rddiv >> 0;
|
||||
}
|
||||
|
||||
//RDDIVH
|
||||
|
@ -221,7 +199,7 @@ uint8 CPU::mmio_r4215() {
|
|||
|
||||
//RDMPYL
|
||||
uint8 CPU::mmio_r4216() {
|
||||
return status.rdmpy;
|
||||
return status.rdmpy >> 0;
|
||||
}
|
||||
|
||||
//RDMPYH
|
||||
|
@ -256,7 +234,7 @@ uint8 CPU::mmio_r43x1(uint8 i) {
|
|||
|
||||
//A1TxL
|
||||
uint8 CPU::mmio_r43x2(uint8 i) {
|
||||
return channel[i].source_addr;
|
||||
return channel[i].source_addr >> 0;
|
||||
}
|
||||
|
||||
//A1TxH
|
||||
|
@ -272,7 +250,7 @@ uint8 CPU::mmio_r43x4(uint8 i) {
|
|||
//DASxL
|
||||
//union { uint16 transfer_size; uint16 indirect_addr; };
|
||||
uint8 CPU::mmio_r43x5(uint8 i) {
|
||||
return channel[i].transfer_size;
|
||||
return channel[i].transfer_size >> 0;
|
||||
}
|
||||
|
||||
//DASxH
|
||||
|
@ -288,7 +266,7 @@ uint8 CPU::mmio_r43x7(uint8 i) {
|
|||
|
||||
//A2AxL
|
||||
uint8 CPU::mmio_r43x8(uint8 i) {
|
||||
return channel[i].hdma_addr;
|
||||
return channel[i].hdma_addr >> 0;
|
||||
}
|
||||
|
||||
//A2AxH
|
||||
|
@ -323,7 +301,7 @@ void CPU::mmio_w43x1(uint8 i, uint8 data) {
|
|||
|
||||
//A1TxL
|
||||
void CPU::mmio_w43x2(uint8 i, uint8 data) {
|
||||
channel[i].source_addr = (channel[i].source_addr & 0xff00) | (data);
|
||||
channel[i].source_addr = (channel[i].source_addr & 0xff00) | (data << 0);
|
||||
}
|
||||
|
||||
//A1TxH
|
||||
|
@ -339,7 +317,7 @@ void CPU::mmio_w43x4(uint8 i, uint8 data) {
|
|||
//DASxL
|
||||
//union { uint16 transfer_size; uint16 indirect_addr; };
|
||||
void CPU::mmio_w43x5(uint8 i, uint8 data) {
|
||||
channel[i].transfer_size = (channel[i].transfer_size & 0xff00) | (data);
|
||||
channel[i].transfer_size = (channel[i].transfer_size & 0xff00) | (data << 0);
|
||||
}
|
||||
|
||||
//DASxH
|
||||
|
@ -355,7 +333,7 @@ void CPU::mmio_w43x7(uint8 i, uint8 data) {
|
|||
|
||||
//A2AxL
|
||||
void CPU::mmio_w43x8(uint8 i, uint8 data) {
|
||||
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data);
|
||||
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data << 0);
|
||||
}
|
||||
|
||||
//A2AxH
|
||||
|
@ -377,6 +355,9 @@ void CPU::mmio_power() {
|
|||
}
|
||||
|
||||
void CPU::mmio_reset() {
|
||||
//$2140-217f
|
||||
foreach(port, status.port) port = 0x00;
|
||||
|
||||
//$2181-$2183
|
||||
status.wram_addr = 0x000000;
|
||||
|
||||
|
@ -386,9 +367,9 @@ void CPU::mmio_reset() {
|
|||
status.joypad2_bits = ~0;
|
||||
|
||||
//$4200
|
||||
status.nmi_enabled = false;
|
||||
status.hirq_enabled = false;
|
||||
status.virq_enabled = false;
|
||||
status.nmi_enabled = false;
|
||||
status.hirq_enabled = false;
|
||||
status.virq_enabled = false;
|
||||
status.auto_joypad_poll = false;
|
||||
|
||||
//$4201
|
||||
|
@ -426,7 +407,7 @@ void CPU::mmio_reset() {
|
|||
//ALU
|
||||
alu.mpyctr = 0;
|
||||
alu.divctr = 0;
|
||||
alu.shift = 0;
|
||||
alu.shift = 0;
|
||||
}
|
||||
|
||||
uint8 CPU::mmio_read(unsigned addr) {
|
||||
|
@ -435,7 +416,7 @@ uint8 CPU::mmio_read(unsigned addr) {
|
|||
//APU
|
||||
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
|
||||
synchronize_smp();
|
||||
return smp.port_read(addr & 3);
|
||||
return smp.port_read(addr);
|
||||
}
|
||||
|
||||
//DMA
|
||||
|
@ -492,7 +473,7 @@ void CPU::mmio_write(unsigned addr, uint8 data) {
|
|||
//APU
|
||||
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
|
||||
synchronize_smp();
|
||||
port_write(addr & 3, data);
|
||||
port_write(addr, data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ void CPU::serialize(serializer &s) {
|
|||
s.integer(status.hdma_pending);
|
||||
s.integer(status.hdma_mode);
|
||||
|
||||
s.array(status.port);
|
||||
|
||||
s.integer(status.wram_addr);
|
||||
|
||||
s.integer(status.joypad_strobe_latch);
|
||||
|
@ -108,11 +110,6 @@ void CPU::serialize(serializer &s) {
|
|||
s.integer(pipe.valid);
|
||||
s.integer(pipe.addr);
|
||||
s.integer(pipe.data);
|
||||
|
||||
s.integer(apu_port[0]);
|
||||
s.integer(apu_port[1]);
|
||||
s.integer(apu_port[2]);
|
||||
s.integer(apu_port[3]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,16 +12,16 @@ void CPU::run_auto_joypad_poll() {
|
|||
joy4 |= (port1 & 2) ? (0x8000 >> i) : 0;
|
||||
}
|
||||
|
||||
status.joy1l = joy1;
|
||||
status.joy1l = joy1 >> 0;
|
||||
status.joy1h = joy1 >> 8;
|
||||
|
||||
status.joy2l = joy2;
|
||||
status.joy2l = joy2 >> 0;
|
||||
status.joy2h = joy2 >> 8;
|
||||
|
||||
status.joy3l = joy3;
|
||||
status.joy3l = joy3 >> 0;
|
||||
status.joy3h = joy3 >> 8;
|
||||
|
||||
status.joy4l = joy4;
|
||||
status.joy4l = joy4 >> 0;
|
||||
status.joy4h = joy4 >> 8;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ private:
|
|||
enum : unsigned {
|
||||
DramRefresh,
|
||||
HdmaRun,
|
||||
ControllerLatch,
|
||||
};
|
||||
};
|
||||
nall::priority_queue<unsigned> queue;
|
||||
|
|
|
@ -122,7 +122,7 @@ void CPU::hdma_run() {
|
|||
}
|
||||
if(channels == 0) return;
|
||||
|
||||
add_clocks(24);
|
||||
add_clocks(16);
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled == false || channel[i].hdma_completed == true) continue;
|
||||
channel[i].dma_enabled = false;
|
||||
|
|
|
@ -158,6 +158,7 @@ void CPU::mmio_write(unsigned addr, uint8 data) {
|
|||
status.irq_transition = false;
|
||||
}
|
||||
|
||||
status.irq_lock = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ void CPU::queue_event(unsigned id) {
|
|||
switch(id) {
|
||||
case QueueEvent::DramRefresh: return add_clocks(40);
|
||||
case QueueEvent::HdmaRun: return hdma_run();
|
||||
case QueueEvent::ControllerLatch: return ppu.latch_counters();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +32,8 @@ void CPU::add_clocks(unsigned clocks) {
|
|||
if(status.virq_enabled) {
|
||||
unsigned cpu_time = vcounter() * 1364 + hcounter();
|
||||
unsigned irq_time = status.vtime * 1364 + status.htime * 4;
|
||||
if(cpu_time > irq_time) irq_time += 262 * 1364;
|
||||
unsigned framelines = (system.region() == System::Region::NTSC ? 262 : 312) + field();
|
||||
if(cpu_time > irq_time) irq_time += framelines * 1364;
|
||||
bool irq_valid = status.irq_valid;
|
||||
status.irq_valid = cpu_time <= irq_time && cpu_time + clocks > irq_time;
|
||||
if(!irq_valid && status.irq_valid) status.irq_line = true;
|
||||
|
@ -66,7 +68,11 @@ void CPU::scanline() {
|
|||
queue.enqueue(534, QueueEvent::DramRefresh);
|
||||
|
||||
if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) {
|
||||
queue.enqueue(1104, QueueEvent::HdmaRun);
|
||||
queue.enqueue(1104 + 8, QueueEvent::HdmaRun);
|
||||
}
|
||||
|
||||
if(vcounter() == input.latchy) {
|
||||
queue.enqueue(input.latchx, QueueEvent::ControllerLatch);
|
||||
}
|
||||
|
||||
bool nmi_valid = status.nmi_valid;
|
||||
|
|
|
@ -105,11 +105,14 @@ void PPU::oam_mmio_write(uint16 addr, uint8 data) {
|
|||
|
||||
if(regs.display_disabled == true) {
|
||||
memory::oam[addr] = data;
|
||||
update_sprite_list(addr, data);
|
||||
} else {
|
||||
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
|
||||
memory::oam[regs.ioamaddr] = data;
|
||||
update_sprite_list(regs.ioamaddr, data);
|
||||
} else {
|
||||
memory::oam[addr] = data;
|
||||
update_sprite_list(addr, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,37 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
void PPU::update_sprite_list(unsigned addr, uint8 data) {
|
||||
if(addr < 0x0200) {
|
||||
unsigned i = addr >> 2;
|
||||
switch(addr & 3) {
|
||||
case 0: sprite_list[i].x = (sprite_list[i].x & 0x0100) | data; break;
|
||||
case 1: sprite_list[i].y = (data + 1) & 0xff; break;
|
||||
case 2: sprite_list[i].character = data; break;
|
||||
case 3: sprite_list[i].vflip = data & 0x80;
|
||||
sprite_list[i].hflip = data & 0x40;
|
||||
sprite_list[i].priority = (data >> 4) & 3;
|
||||
sprite_list[i].palette = (data >> 1) & 7;
|
||||
sprite_list[i].use_nameselect = data & 0x01;
|
||||
}
|
||||
} else {
|
||||
unsigned i = (addr & 0x1f) << 2;
|
||||
sprite_list[i + 0].x = ((data & 0x01) << 8) | (sprite_list[i + 0].x & 0xff);
|
||||
sprite_list[i + 0].size = data & 0x02;
|
||||
sprite_list[i + 1].x = ((data & 0x04) << 6) | (sprite_list[i + 1].x & 0xff);
|
||||
sprite_list[i + 1].size = data & 0x08;
|
||||
sprite_list[i + 2].x = ((data & 0x10) << 4) | (sprite_list[i + 2].x & 0xff);
|
||||
sprite_list[i + 2].size = data & 0x20;
|
||||
sprite_list[i + 3].x = ((data & 0x40) << 2) | (sprite_list[i + 3].x & 0xff);
|
||||
sprite_list[i + 3].size = data & 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::build_sprite_list() {
|
||||
if(sprite_list_valid == true) return;
|
||||
sprite_list_valid = true;
|
||||
|
||||
const uint8 *tableA = memory::oam.data();
|
||||
const uint8 *tableB = memory::oam.data() + 512;
|
||||
|
||||
for(unsigned i = 0; i < 128; i++) {
|
||||
const bool x = *tableB & (1 << ((i & 3) << 1)); //0x01, 0x04, 0x10, 0x40
|
||||
const bool size = *tableB & (2 << ((i & 3) << 1)); //0x02, 0x08, 0x20, 0x80
|
||||
const bool size = sprite_list[i].size;
|
||||
|
||||
switch(cache.oam_basesize) {
|
||||
case 0: sprite_list[i].width = (!size) ? 8 : 16;
|
||||
|
@ -40,18 +62,6 @@ void PPU::build_sprite_list() {
|
|||
if(regs.oam_interlace && !size) sprite_list[i].height = 16;
|
||||
break;
|
||||
}
|
||||
|
||||
sprite_list[i].x = (x << 8) + tableA[0];
|
||||
sprite_list[i].y = (tableA[1] + 1) & 0xff;
|
||||
sprite_list[i].character = tableA[2];
|
||||
sprite_list[i].vflip = tableA[3] & 0x80;
|
||||
sprite_list[i].hflip = tableA[3] & 0x40;
|
||||
sprite_list[i].priority = (tableA[3] >> 4) & 3;
|
||||
sprite_list[i].palette = (tableA[3] >> 1) & 7;
|
||||
sprite_list[i].use_nameselect = tableA[3] & 1;
|
||||
|
||||
tableA += 4;
|
||||
if((i & 3) == 3) tableB++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ struct sprite_item {
|
|||
bool vflip, hflip;
|
||||
uint8 palette;
|
||||
uint8 priority;
|
||||
bool size;
|
||||
} sprite_list[128];
|
||||
bool sprite_list_valid;
|
||||
unsigned active_sprite;
|
||||
|
@ -75,6 +76,7 @@ struct oam_tileitem {
|
|||
enum { OAM_PRI_NONE = 4 };
|
||||
uint8 oam_line_pal[256], oam_line_pri[256];
|
||||
|
||||
void update_sprite_list(unsigned addr, uint8 data);
|
||||
void build_sprite_list();
|
||||
bool is_sprite_on_scanline();
|
||||
void load_oam_tiles();
|
||||
|
|
|
@ -180,6 +180,7 @@ void PPU::serialize(serializer &s) {
|
|||
s.integer(sprite_list[n].hflip);
|
||||
s.integer(sprite_list[n].palette);
|
||||
s.integer(sprite_list[n].priority);
|
||||
s.integer(sprite_list[n].size);
|
||||
}
|
||||
s.integer(sprite_list_valid);
|
||||
s.integer(active_sprite);
|
||||
|
|
|
@ -82,6 +82,7 @@ private:
|
|||
|
||||
friend class System;
|
||||
friend class Video;
|
||||
friend class CPU;
|
||||
};
|
||||
|
||||
extern Input input;
|
||||
|
|
|
@ -11,12 +11,12 @@ alwaysinline void SMP::ram_write(uint16 addr, uint8 data) {
|
|||
if(status.ram_writable && !status.ram_disabled) memory::apuram[addr] = data;
|
||||
}
|
||||
|
||||
uint8 SMP::port_read(uint8 port) {
|
||||
return memory::apuram[0xf4 + (port & 3)];
|
||||
uint8 SMP::port_read(uint2 port) const {
|
||||
return memory::apuram[0xf4 + port];
|
||||
}
|
||||
|
||||
void SMP::port_write(uint8 port, uint8 data) {
|
||||
memory::apuram[0xf4 + (port & 3)] = data;
|
||||
void SMP::port_write(uint2 port, uint8 data) {
|
||||
memory::apuram[0xf4 + port] = data;
|
||||
}
|
||||
|
||||
alwaysinline uint8 SMP::op_busread(uint16 addr) {
|
||||
|
@ -45,15 +45,15 @@ alwaysinline uint8 SMP::op_busread(uint16 addr) {
|
|||
case 0xf6: //CPUIO2
|
||||
case 0xf7: { //CPUIO3
|
||||
synchronize_cpu();
|
||||
r = cpu.port_read(addr & 3);
|
||||
r = cpu.port_read(addr);
|
||||
} break;
|
||||
|
||||
case 0xf8: { //RAM0
|
||||
r = status.smp_f8;
|
||||
r = status.ram0;
|
||||
} break;
|
||||
|
||||
case 0xf9: { //RAM1
|
||||
r = status.smp_f9;
|
||||
r = status.ram1;
|
||||
} break;
|
||||
|
||||
case 0xfa: //T0TARGET
|
||||
|
@ -146,7 +146,7 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
} break;
|
||||
|
||||
case 0xf3: { //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||
if(!(status.dsp_addr & 0x80)) {
|
||||
dsp.write(status.dsp_addr & 0x7f, data);
|
||||
}
|
||||
|
@ -157,15 +157,15 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
case 0xf6: //CPUIO2
|
||||
case 0xf7: { //CPUIO3
|
||||
synchronize_cpu();
|
||||
port_write(addr & 3, data);
|
||||
port_write(addr, data);
|
||||
} break;
|
||||
|
||||
case 0xf8: { //RAM0
|
||||
status.smp_f8 = data;
|
||||
status.ram0 = data;
|
||||
} break;
|
||||
|
||||
case 0xf9: { //RAM1
|
||||
status.smp_f9 = data;
|
||||
status.ram1 = data;
|
||||
} break;
|
||||
|
||||
case 0xfa: { //T0TARGET
|
||||
|
|
|
@ -19,8 +19,8 @@ void SMP::serialize(serializer &s) {
|
|||
|
||||
s.integer(status.dsp_addr);
|
||||
|
||||
s.integer(status.smp_f8);
|
||||
s.integer(status.smp_f9);
|
||||
s.integer(status.ram0);
|
||||
s.integer(status.ram1);
|
||||
|
||||
s.integer(t0.stage0_ticks);
|
||||
s.integer(t0.stage1_ticks);
|
||||
|
|
|
@ -65,26 +65,26 @@ void SMP::reset() {
|
|||
create(Enter, system.apu_frequency());
|
||||
|
||||
regs.pc = 0xffc0;
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.sp = 0xef;
|
||||
regs.p = 0x02;
|
||||
regs.p = 0x02;
|
||||
|
||||
for(unsigned i = 0; i < memory::apuram.size(); i++) {
|
||||
memory::apuram.write(i, 0x00);
|
||||
}
|
||||
|
||||
status.clock_counter = 0;
|
||||
status.dsp_counter = 0;
|
||||
status.timer_step = 3;
|
||||
status.dsp_counter = 0;
|
||||
status.timer_step = 3;
|
||||
|
||||
//$00f0
|
||||
status.clock_speed = 0;
|
||||
status.timer_speed = 0;
|
||||
status.timers_enabled = true;
|
||||
status.ram_disabled = false;
|
||||
status.ram_writable = true;
|
||||
status.clock_speed = 0;
|
||||
status.timer_speed = 0;
|
||||
status.timers_enabled = true;
|
||||
status.ram_disabled = false;
|
||||
status.ram_writable = true;
|
||||
status.timers_disabled = false;
|
||||
|
||||
//$00f1
|
||||
|
@ -94,8 +94,8 @@ void SMP::reset() {
|
|||
status.dsp_addr = 0x00;
|
||||
|
||||
//$00f8,$00f9
|
||||
status.smp_f8 = 0x00;
|
||||
status.smp_f9 = 0x00;
|
||||
status.ram0 = 0x00;
|
||||
status.ram1 = 0x00;
|
||||
|
||||
t0.stage0_ticks = 0;
|
||||
t1.stage0_ticks = 0;
|
||||
|
|
|
@ -5,8 +5,8 @@ public:
|
|||
alwaysinline void synchronize_cpu();
|
||||
alwaysinline void synchronize_dsp();
|
||||
|
||||
uint8 port_read(uint8 port);
|
||||
void port_write(uint8 port, uint8 data);
|
||||
uint8 port_read(uint2 port) const;
|
||||
void port_write(uint2 port, uint8 data);
|
||||
|
||||
void enter();
|
||||
void power();
|
||||
|
@ -43,7 +43,8 @@ private:
|
|||
uint8 dsp_addr;
|
||||
|
||||
//$00f8,$00f9
|
||||
uint8 smp_f8, smp_f9;
|
||||
uint8 ram0;
|
||||
uint8 ram1;
|
||||
} status;
|
||||
|
||||
static void Enter();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "067.22";
|
||||
static const char Version[] = "067.23";
|
||||
static const unsigned SerializerVersion = 12;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ namespace SNES {
|
|||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
using namespace nall;
|
||||
|
||||
|
@ -38,15 +39,20 @@ using namespace nall;
|
|||
#endif
|
||||
|
||||
namespace SNES {
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
typedef uint8_t uint8;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef uint_t<2> uint2;
|
||||
typedef uint_t<10> uint10;
|
||||
typedef uint_t<17> uint17;
|
||||
typedef uint_t<24> uint24;
|
||||
|
||||
struct Processor {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
|
|
Loading…
Reference in New Issue