diff --git a/bsnes/nes/cartridge/board/konami-vrc2.cpp b/bsnes/nes/cartridge/board/konami-vrc2.cpp index 5953377b..164fe848 100755 --- a/bsnes/nes/cartridge/board/konami-vrc2.cpp +++ b/bsnes/nes/cartridge/board/konami-vrc2.cpp @@ -1,17 +1,29 @@ struct KonamiVRC2 : Board { +struct Settings { + struct Pinout { + unsigned a0; + unsigned a1; + } pinout; +} settings; + VRC2 vrc2; -bool latch; uint8 prg_read(unsigned addr) { - if(addr == 0x6000) return latch; - if(addr & 0x8000) return prgrom.read(vrc2.prg_addr(addr)); - return cpu.mdr(); + if(addr < 0x6000) return cpu.mdr(); + if(addr < 0x8000) return vrc2.ram_read(addr); + return prgrom.read(vrc2.prg_addr(addr)); } void prg_write(unsigned addr, uint8 data) { - if(addr == 0x6000) latch = data & 0x01; - if(addr & 0x8000) return vrc2.reg_write(addr, data); + if(addr < 0x6000) return; + if(addr < 0x8000) return vrc2.ram_write(addr, data); + + bool a0 = (addr & settings.pinout.a0); + bool a1 = (addr & settings.pinout.a1); + addr &= 0xfff0; + addr |= (a0 << 0) | (a1 << 1); + return vrc2.reg_write(addr, data); } uint8 chr_read(unsigned addr) { @@ -30,16 +42,16 @@ void power() { void reset() { vrc2.reset(); - latch = 0; } void serialize(serializer &s) { Board::serialize(s); vrc2.serialize(s); - s.integer(latch); } KonamiVRC2(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc2(*this) { + settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].value); + settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].value); } }; diff --git a/bsnes/nes/cartridge/chip/vrc2.cpp b/bsnes/nes/cartridge/chip/vrc2.cpp index 6d46e1e6..207387fb 100755 --- a/bsnes/nes/cartridge/chip/vrc2.cpp +++ b/bsnes/nes/cartridge/chip/vrc2.cpp @@ -1,16 +1,17 @@ struct VRC2 : Chip { -uint4 prg_bank[2]; +uint5 prg_bank[2]; uint8 chr_bank[8]; uint2 mirror; +bool latch; unsigned prg_addr(unsigned addr) const { unsigned bank; switch(addr & 0xe000) { case 0x8000: bank = prg_bank[0]; break; case 0xa000: bank = prg_bank[1]; break; - case 0xc000: bank = 0x0e; break; - case 0xe000: bank = 0x0f; break; + case 0xc000: bank = 0x1e; break; + case 0xe000: bank = 0x1f; break; } return (bank * 0x2000) + (addr & 0x1fff); } @@ -30,10 +31,26 @@ unsigned ciram_addr(unsigned addr) const { throw; } +uint8 ram_read(unsigned addr) { + if(board.prgram.size == 0) { + if((addr & 0xf000) == 0x6000) return cpu.mdr() | latch; + return cpu.mdr(); + } + return board.prgram.read(addr & 0x1fff); +} + +void ram_write(unsigned addr, uint8 data) { + if(board.prgram.size == 0) { + if((addr & 0xf000) == 0x6000) latch = data & 0x01; + return; + } + return board.prgram.write(addr & 0x1fff, data); +} + void reg_write(unsigned addr, uint8 data) { switch(addr) { case 0x8000: case 0x8001: case 0x8002: case 0x8003: - prg_bank[0] = data & 0x0f; + prg_bank[0] = data & 0x1f; break; case 0x9000: case 0x9001: case 0x9002: case 0x9003: @@ -41,7 +58,7 @@ void reg_write(unsigned addr, uint8 data) { break; case 0xa000: case 0xa001: case 0xa002: case 0xa003: - prg_bank[1] = data & 0x0f; + prg_bank[1] = data & 0x1f; break; case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break; @@ -77,12 +94,14 @@ void reset() { for(auto &n : prg_bank) n = 0; for(auto &n : chr_bank) n = 0; mirror = 0; + latch = 0; } void serialize(serializer &s) { for(auto &n : prg_bank) s.integer(n); for(auto &n : chr_bank) s.integer(n); s.integer(mirror); + s.integer(latch); } VRC2(Board &board) : Chip(board) { diff --git a/bsnes/nes/cartridge/chip/vrc4.cpp b/bsnes/nes/cartridge/chip/vrc4.cpp index 4a9c3290..10c93ee9 100755 --- a/bsnes/nes/cartridge/chip/vrc4.cpp +++ b/bsnes/nes/cartridge/chip/vrc4.cpp @@ -49,6 +49,32 @@ void main() { } } +unsigned prg_addr(unsigned addr) const { + unsigned bank = 0, banks = board.prgrom.size / 0x2000; + switch(addr & 0xe000) { + case 0x8000: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break; + case 0xa000: bank = prg_bank[1]; break; + case 0xc000: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break; + case 0xe000: bank = banks - 1; break; + } + return (bank * 0x2000) + (addr & 0x1fff); +} + +unsigned chr_addr(unsigned addr) const { + unsigned bank = chr_bank[addr / 0x0400]; + return (bank * 0x0400) + (addr & 0x03ff); +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) + case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) + } + throw; +} + void reg_write(unsigned addr, uint8 data) { switch(addr) { case 0x8000: case 0x8001: case 0x8002: case 0x8003: @@ -117,32 +143,6 @@ void reg_write(unsigned addr, uint8 data) { } } -unsigned prg_addr(unsigned addr) const { - unsigned bank = 0, banks = board.prgrom.size / 0x2000; - switch((addr / 0x2000) & 3) { - case 0: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break; - case 1: bank = prg_bank[1]; break; - case 2: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break; - case 3: bank = banks - 1; break; - } - return (bank * 0x2000) + (addr & 0x1fff); -} - -unsigned chr_addr(unsigned addr) const { - unsigned bank = chr_bank[addr / 0x0400]; - return (bank * 0x0400) + (addr & 0x03ff); -} - -unsigned ciram_addr(unsigned addr) const { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) - case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) - } - throw; -} - void power() { } diff --git a/bsnes/nes/cartridge/ines.cpp b/bsnes/nes/cartridge/ines.cpp index cf1e3f95..b14f81c9 100755 --- a/bsnes/nes/cartridge/ines.cpp +++ b/bsnes/nes/cartridge/ines.cpp @@ -14,7 +14,7 @@ static string iNES(const uint8_t *data, unsigned size) { unsigned prgram = 0; unsigned chrram = chrrom == 0 ? 8192 : 0; - print("iNES mapper: ", mapper, "\n"); +//print("iNES mapper: ", mapper, "\n"); output.append("cartridge\n"); @@ -81,9 +81,6 @@ static string iNES(const uint8_t *data, unsigned size) { case 21: case 23: case 25: - //VRC2 - //output.append("\tboard type:KONAMI-VRC-2\n"); - //output.append("\t\tchip type:VRC2\n"); //VRC4 output.append("\tboard type:KONAMI-VRC-4\n"); output.append("\t\tchip type:VRC4\n"); @@ -91,6 +88,13 @@ static string iNES(const uint8_t *data, unsigned size) { prgram = 8192; break; + case 22: + //VRC2 + output.append("\tboard type:KONAMI-VRC-2\n"); + output.append("\t\tchip type:VRC2\n"); + output.append("\t\t\tpinout a0=0 a1=1\n"); + break; + case 24: output.append("\tboard type:KONAMI-VRC-6\n"); output.append("\t\tchip type:VRC6\n"); @@ -140,7 +144,7 @@ static string iNES(const uint8_t *data, unsigned size) { output.append("\t\tprg rom=", prgrom, " ram=", prgram, "\n"); output.append("\t\tchr rom=", chrrom, " ram=", chrram, "\n"); - print(output, "\n"); +//print(output, "\n"); return output; } diff --git a/bsnes/ui/general/file-browser.cpp b/bsnes/ui/general/file-browser.cpp index c250c867..671fb3d6 100755 --- a/bsnes/ui/general/file-browser.cpp +++ b/bsnes/ui/general/file-browser.cpp @@ -39,6 +39,7 @@ FileBrowser::FileBrowser() { setPath(path); }; + fileList.onChange = { &FileBrowser::synchronize, this }; fileList.onActivate = openButton.onTick = { &FileBrowser::fileListActivate, this }; filterModes.append({ "Default", "", { "*" } }); @@ -53,6 +54,11 @@ FileBrowser::FileBrowser() { for(auto &mode : filterModes) config.attach(mode.path, mode.name); config.load(application->path("paths.cfg")); config.save(application->path("paths.cfg")); + synchronize(); +} + +void FileBrowser::synchronize() { + openButton.setEnabled(fileList.selected()); } FileBrowser::~FileBrowser() { @@ -103,6 +109,7 @@ void FileBrowser::setPath(const string &path) { for(auto &fileName : fileNameList) fileList.append(fileName); fileList.setSelection(0); fileList.setFocused(); + synchronize(); } void FileBrowser::fileListActivate() { diff --git a/bsnes/ui/general/file-browser.hpp b/bsnes/ui/general/file-browser.hpp index e095fcb6..93ce2fef 100755 --- a/bsnes/ui/general/file-browser.hpp +++ b/bsnes/ui/general/file-browser.hpp @@ -27,6 +27,7 @@ private: lstring fileNameList; function callback; + void synchronize(); void setPath(const string &path); void fileListActivate(); bool loadFolder(const string &path); diff --git a/bsnes/ui/general/main-window.cpp b/bsnes/ui/general/main-window.cpp index 8db65368..9f6f749d 100755 --- a/bsnes/ui/general/main-window.cpp +++ b/bsnes/ui/general/main-window.cpp @@ -297,7 +297,7 @@ MainWindow::MainWindow() { settingsMuteAudio.onTick = [&] { config->audio.mute = settingsMuteAudio.checked(); - dspaudio.setVolume(config->audio.mute == false ? 1.0 : 0.0); + dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0); }; settingsConfiguration.onTick = [&] { settingsWindow->setVisible(); }; diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index e2552ac2..9c5cddea 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -27,7 +27,7 @@ void Application::run() { } Application::Application(int argc, char **argv) { - title = "bsnes v083.10"; + title = "bsnes v084"; application = this; quit = false; @@ -76,7 +76,11 @@ Application::Application(int argc, char **argv) { video.driver(config->video.driver); video.set(Video::Handle, mainWindow->viewport.handle()); video.set(Video::Synchronize, config->video.synchronize); - video.init(); + if(video.init() == false) { + MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->video.driver, " video driver." }); + video.driver("None"); + video.init(); + } utility->bindVideoFilter(); utility->bindVideoShader(); @@ -85,17 +89,25 @@ Application::Application(int argc, char **argv) { audio.set(Audio::Synchronize, config->audio.synchronize); audio.set(Audio::Latency, config->audio.latency); audio.set(Audio::Frequency, config->audio.frequency); - audio.init(); + if(audio.init() == false) { + MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->audio.driver, " audio driver." }); + audio.driver("None"); + audio.init(); + } dspaudio.setPrecision(16); - dspaudio.setVolume(config->audio.mute == false ? 1.0 : 0.0); + dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0); dspaudio.setBalance(0.0); dspaudio.setResampler(DSP::ResampleEngine::Sinc); dspaudio.setResamplerFrequency(config->audio.frequency); input.driver(config->input.driver); input.set(Input::Handle, mainWindow->viewport.handle()); - input.init(); + if(input.init() == false) { + MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->input.driver, " input driver." }); + input.driver("None"); + input.init(); + } if(config->video.startFullScreen) utility->toggleFullScreen(); if(argc == 2) interface->loadCartridge(argv[1]); diff --git a/bsnes/ui/utility/utility.cpp b/bsnes/ui/utility/utility.cpp index 25e7fa56..9a4831af 100755 --- a/bsnes/ui/utility/utility.cpp +++ b/bsnes/ui/utility/utility.cpp @@ -8,6 +8,7 @@ void Utility::setMode(Interface::Mode mode) { mainWindow->nesMenu.setVisible(false); mainWindow->snesMenu.setVisible(false); mainWindow->gameBoyMenu.setVisible(false); + mainWindow->viewport.setVisible(mode != Interface::Mode::None); if(mode == Interface::Mode::None) { mainWindow->setTitle(application->title); diff --git a/snesfilter/HQ2x/HQ2x-RGB555.cpp b/snesfilter/HQ2x/HQ2x-RGB555.cpp new file mode 100755 index 00000000..89aa1e70 --- /dev/null +++ b/snesfilter/HQ2x/HQ2x-RGB555.cpp @@ -0,0 +1,206 @@ +#include +#include +using namespace nall; + +extern "C" { + void filter_size(unsigned&, unsigned&); + void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); +}; + +enum { + diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407, + diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0, +}; + +uint32_t *yuvTable; +uint8_t rotate[256]; + +const uint8_t hqTable[256] = { + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13, + 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14, + 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14, +}; + +static void initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + yuvTable = new uint32_t[32768]; + + for(unsigned i = 0; i < 32768; i++) { + uint8_t R = (i >> 0) & 31; + uint8_t G = (i >> 5) & 31; + uint8_t B = (i >> 10) & 31; + + //bgr555->bgr888 + double r = (R << 3) | (R >> 2); + double g = (G << 3) | (G >> 2); + double b = (B << 3) | (B >> 2); + + //bgr888->yuv + double y = (r + g + b) * (0.25f * (63.5f / 48.0f)); + double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f); + double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f); + + yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v); + } + + //counter-clockwise rotation table; one revolution: + //123 369 12346789 + //4.6 -> 2.8 = + //789 147 36928147 + for(unsigned n = 0; n < 256; n++) { + rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88) + | ((n & 0x01) << 5) | ((n & 0x08) << 3) + | ((n & 0x10) >> 3) | ((n & 0x80) >> 5); + } +} + +static void terminate() { + delete[] yuvTable; +} + +static bool same(uint16_t x, uint16_t y) { + return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask); +} + +static bool diff(uint32_t x, uint16_t y) { + return ((x - yuvTable[y]) & diff_mask); +} + +static void grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; } +static uint16_t pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); } + +static uint16_t blend1(uint32_t A, uint32_t B) { + grow(A); grow(B); + return pack((A * 3 + B) >> 2); +} + +static uint16_t blend2(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 2 + B + C) >> 2); +} + +static uint16_t blend3(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 5 + B * 2 + C) >> 3); +} + +static uint16_t blend4(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 6 + B + C) >> 3); +} + +static uint16_t blend5(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 2 + (B + C) * 3) >> 3); +} + +static uint16_t blend6(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 14 + B + C) >> 4); +} + +static uint16_t blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) { + switch(rule) { default: + case 0: return E; + case 1: return blend1(E, A); + case 2: return blend1(E, D); + case 3: return blend1(E, B); + case 4: return blend2(E, D, B); + case 5: return blend2(E, A, B); + case 6: return blend2(E, A, D); + case 7: return blend3(E, B, D); + case 8: return blend3(E, D, B); + case 9: return blend4(E, D, B); + case 10: return blend5(E, D, B); + case 11: return blend6(E, D, B); + case 12: return same(B, D) ? blend2(E, D, B) : E; + case 13: return same(B, D) ? blend5(E, D, B) : E; + case 14: return same(B, D) ? blend6(E, D, B) : E; + case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A); + case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A); + case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A); + case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D); + case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B); + } +} + +dllexport void filter_size(unsigned &width, unsigned &height) { + initialize(); + width *= 2; + height *= 2; +} + +dllexport void filter_render( + uint16_t *output, unsigned outputPitch, + const uint16_t *input, unsigned inputPitch, + unsigned width, unsigned height +) { + initialize(); + outputPitch >>= 1, inputPitch >>= 1; + + #pragma omp parallel for + for(unsigned y = 0; y < height; y++) { + const uint16_t *in = input + y * inputPitch; + uint16_t *out0 = output + y * outputPitch * 2; + uint16_t *out1 = output + y * outputPitch * 2 + outputPitch; + + int prevline = (y == 0 ? 0 : inputPitch); + int nextline = (y == height - 1 ? 0 : inputPitch); + + in++; + *out0++ = 0; *out0++ = 0; + *out1++ = 0; *out1++ = 0; + + for(unsigned x = 1; x < width - 1; x++) { + uint16_t A = *(in - prevline - 1); + uint16_t B = *(in - prevline + 0); + uint16_t C = *(in - prevline + 1); + uint16_t D = *(in - 1); + uint16_t E = *(in + 0); + uint16_t F = *(in + 1); + uint16_t G = *(in + nextline - 1); + uint16_t H = *(in + nextline + 0); + uint16_t I = *(in + nextline + 1); + uint32_t e = yuvTable[E] + diff_offset; + + uint8_t pattern; + pattern = diff(e, A) << 0; + pattern |= diff(e, B) << 1; + pattern |= diff(e, C) << 2; + pattern |= diff(e, D) << 3; + pattern |= diff(e, F) << 4; + pattern |= diff(e, G) << 5; + pattern |= diff(e, H) << 6; + pattern |= diff(e, I) << 7; + + *(out0 + 0) = blend(hqTable[pattern], E, A, B, D, F, H); pattern = rotate[pattern]; + *(out0 + 1) = blend(hqTable[pattern], E, C, F, B, H, D); pattern = rotate[pattern]; + *(out1 + 1) = blend(hqTable[pattern], E, I, H, F, D, B); pattern = rotate[pattern]; + *(out1 + 0) = blend(hqTable[pattern], E, G, D, H, B, F); + + in++; + out0 += 2; + out1 += 2; + } + + in++; + *out0++ = 0; *out0++ = 0; + *out1++ = 0; *out1++ = 0; + } +}