diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index 7dd97846..5c688ac2 100755 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "bsnes"; - static const char Version[] = "089.09"; + static const char Version[] = "089.10"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; } diff --git a/bsnes/sfc/chip/spc7110/alu.cpp b/bsnes/sfc/chip/spc7110/alu.cpp index 99f351f8..68757d65 100755 --- a/bsnes/sfc/chip/spc7110/alu.cpp +++ b/bsnes/sfc/chip/spc7110/alu.cpp @@ -1,6 +1,8 @@ #ifdef SPC7110_CPP void SPC7110::alu_multiply() { + add_clocks(30); + if(r482e & 1) { //signed 16-bit x 16-bit multiplication int16 r0 = (int16)(r4824 | r4825 << 8); @@ -27,6 +29,8 @@ void SPC7110::alu_multiply() { } void SPC7110::alu_divide() { + add_clocks(40); + if(r482e & 1) { //signed 32-bit x 16-bit division int32 dividend = (int32)(r4820 | r4821 << 8 | r4822 << 16 | r4823 << 24); diff --git a/bsnes/sfc/chip/spc7110/data.cpp b/bsnes/sfc/chip/spc7110/data.cpp index b89cfe73..98589c84 100755 --- a/bsnes/sfc/chip/spc7110/data.cpp +++ b/bsnes/sfc/chip/spc7110/data.cpp @@ -1,14 +1,10 @@ #ifdef SPC7110_CPP uint8 SPC7110::datarom_read(unsigned addr) { - unsigned mask = (1 << (r4834 & 3)) - 1; //8mbit, 16mbit, 32mbit, 64mbit - unsigned range = 0x100000 * (1 + mask); - unsigned offset = addr & 0x7fffff; - - //mirroring behavior is non-sensical. assuming a 32mbit data ROM: - //banks 4-7 with mask 0-2 returns 0x00; banks 4-7 with mask 3 mirrors banks 0-3 - if(range <= drom_size && offset >= drom_size) return 0x00; - + unsigned size = 1 << (r4834 & 3); //size in MB + unsigned mask = 0x100000 * size - 1; + unsigned offset = addr & mask; + if((r4834 & 3) != 3 && (addr & 0x400000)) return 0x00; return cartridge.rom.read(drom_base + Bus::mirror(offset, drom_size)); } @@ -33,6 +29,7 @@ void SPC7110::data_port_increment_4810() { if(r4818 & 8) adjust = (int16)adjust; if((r4818 & 16) == 0) set_data_offset(offset + stride); if((r4818 & 16) != 0) set_data_adjust(adjust + stride); + data_port_read(); } void SPC7110::data_port_increment_4814() { @@ -41,6 +38,7 @@ void SPC7110::data_port_increment_4814() { unsigned adjust = data_adjust(); if(r4818 & 8) adjust = (int16)adjust; set_data_offset(offset + adjust); + data_port_read(); } void SPC7110::data_port_increment_4815() { @@ -49,6 +47,7 @@ void SPC7110::data_port_increment_4815() { unsigned adjust = data_adjust(); if(r4818 & 8) adjust = (int16)adjust; set_data_offset(offset + adjust); + data_port_read(); } void SPC7110::data_port_increment_481a() { @@ -57,6 +56,7 @@ void SPC7110::data_port_increment_481a() { unsigned adjust = data_adjust(); if(r4818 & 8) adjust = (int16)adjust; set_data_offset(offset + adjust); + data_port_read(); } #endif diff --git a/bsnes/sfc/chip/spc7110/dcu.cpp b/bsnes/sfc/chip/spc7110/dcu.cpp index 99d7ccad..a7dd9ff7 100755 --- a/bsnes/sfc/chip/spc7110/dcu.cpp +++ b/bsnes/sfc/chip/spc7110/dcu.cpp @@ -1,3 +1,5 @@ +#include "decompressor.cpp" + void SPC7110::dcu_load_address() { unsigned table = r4801 | r4802 << 8 | r4803 << 16; unsigned index = r4804 << 2; @@ -10,29 +12,26 @@ void SPC7110::dcu_load_address() { } void SPC7110::dcu_begin_transfer() { - switch(dcu_mode) { - case 0: decompress_1bpp(true); break; - case 1: decompress_2bpp(true); break; - case 2: decompress_4bpp(true); break; - case 3: return; - } + if(dcu_mode == 3) return; //invalid mode - r480c |= 0x80; - dcu_sp = 0; - - //reset context states - for(auto &ctx : context) { - ctx.index = 0; - ctx.invert = 0; - } + add_clocks(20); + decompressor->initialize(dcu_mode, dcu_addr); if(r480b & 2) { unsigned seek = (r4805 | r4806 << 8) << dcu_mode; - while(seek--) dcu_read(); + add_clocks(seek); + while(seek--) decompressor->output(); } + + r480c |= 0x80; } uint8 SPC7110::dcu_read() { + if((r480c & 0x80) == 0) return 0x00; + return decompressor->output(); +} + +/* unsigned tilesize = 8 << dcu_mode; if(dcu_sp == 0) { @@ -51,290 +50,9 @@ uint8 SPC7110::dcu_read() { uint8 data = dcu_output[dcu_sp++]; dcu_sp &= tilesize - 1; return data; -} - -// - -void SPC7110::decompress_1bpp(bool init) { - static uint8 val, in, span; - static int out, inverts, lps, in_count; - - if(init == true) { - out = inverts = lps = 0; - span = 0xff; - val = datarom_read(dcu_addr++); - in = datarom_read(dcu_addr++); - in_count = 8; - return; - } - - for(unsigned row = 0; row < 8; row++) { - for(unsigned bit = 0; bit < 8; bit++) { - //get context - uint8 mask = (1 << (bit & 3)) - 1; - uint8 con = mask + ((inverts & mask) ^ (lps & mask)); - if(bit > 3) con += 15; - - //get prob and mps - unsigned prob = probability(con); - unsigned mps = (((out >> 15) & 1) ^ context[con].invert); - - //get bit - unsigned flag_lps; - if(val <= span - prob) { //mps - span = span - prob; - out = (out << 1) + mps; - flag_lps = 0; - } else { //lps - val = val - (span - (prob - 1)); - span = prob - 1; - out = (out << 1) + 1 - mps; - flag_lps = 1; - } - - //renormalize - unsigned shift = 0; - while(span < 0x7f) { - shift++; - - span = (span << 1) + 1; - val = (val << 1) + (in >> 7); - - in <<= 1; - if(--in_count == 0) { - in = datarom_read(dcu_addr++); - in_count = 8; - } - } - - //update processing info - lps = (lps << 1) + flag_lps; - inverts = (inverts << 1) + context[con].invert; - - //update context state - if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; - if(flag_lps) context[con].index = next_lps(con); - else if(shift) context[con].index = next_mps(con); - } - - //save byte - dcu_tiledata[dcu_dp + row] = out; - } -} - -void SPC7110::decompress_2bpp(bool init) { - static int pixelorder[4], realorder[4]; - static uint8 in, val, span; - static int out, inverts, lps, in_count; - - if(init == true) { - for(unsigned i = 0; i < 4; i++) pixelorder[i] = i; - out = inverts = lps = 0; - span = 0xff; - val = datarom_read(dcu_addr++); - in = datarom_read(dcu_addr++); - in_count = 8; - return; - } - - for(unsigned row = 0; row < 8; row++) { - for(unsigned pixel = 0; pixel < 8; pixel++) { - //get first symbol context - unsigned a = ((out >> (1 * 2)) & 3); - unsigned b = ((out >> (7 * 2)) & 3); - unsigned c = ((out >> (8 * 2)) & 3); - unsigned con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); - - //update pixel order - unsigned m, n; - for(m = 0; m < 4; m++) if(pixelorder[m] == a) break; - for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1]; - pixelorder[0] = a; - - //calculate the real pixel order - for(m = 0; m < 4; m++) realorder[m] = pixelorder[m]; - - //rotate reference pixel c value to top - for(m = 0; m < 4; m++) if(realorder[m] == c) break; - for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; - realorder[0] = c; - - //rotate reference pixel b value to top - for(m = 0; m < 4; m++) if(realorder[m] == b) break; - for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; - realorder[0] = b; - - //rotate reference pixel a value to top - for(m = 0; m < 4; m++) if(realorder[m] == a) break; - for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; - realorder[0] = a; - - //get 2 symbols - for(unsigned bit = 0; bit < 2; bit++) { - //get prob - unsigned prob = probability(con); - - //get symbol - unsigned flag_lps; - if(val <= span - prob) { //mps - span = span - prob; - flag_lps = 0; - } else { //lps - val = val - (span - (prob - 1)); - span = prob - 1; - flag_lps = 1; - } - - //renormalize - unsigned shift = 0; - while(span < 0x7f) { - shift++; - - span = (span << 1) + 1; - val = (val << 1) + (in >> 7); - - in <<= 1; - if(--in_count == 0) { - in = datarom_read(dcu_addr++); - in_count = 8; - } - } - - //update processing info - lps = (lps << 1) + flag_lps; - inverts = (inverts << 1) + context[con].invert; - - //update context state - if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; - if(flag_lps) context[con].index = next_lps(con); - else if(shift) context[con].index = next_mps(con); - - //get next context - con = 5 + (con << 1) + ((lps ^ inverts) & 1); - } - - //get pixel - b = realorder[(lps ^ inverts) & 3]; - out = (out << 2) + b; - } - - //turn pixel data into bitplanes - unsigned data = deinterleave_2x8(out); - dcu_tiledata[dcu_dp + row * 2 + 0] = data >> 8; - dcu_tiledata[dcu_dp + row * 2 + 1] = data >> 0; - } -} - -void SPC7110::decompress_4bpp(bool init) { - static int pixelorder[16], realorder[16]; - static uint8 in, val, span; - static int out0, out1, inverts, lps, in_count; - - if(init == true) { - for(unsigned i = 0; i < 16; i++) pixelorder[i] = i; - out0 = out1 = inverts = lps = 0; - span = 0xff; - val = datarom_read(dcu_addr++); - in = datarom_read(dcu_addr++); - in_count = 8; - return; - } - - for(unsigned row = 0; row < 8; row++) { - for(unsigned pixel = 0; pixel < 8; pixel++) { - //get first symbol context - unsigned a = ((out0 >> (0 * 4)) & 15); - unsigned b = ((out0 >> (7 * 4)) & 15); - unsigned c = ((out1 >> (0 * 4)) & 15); - unsigned con = 0; - unsigned refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); - - //update pixel order - unsigned m, n; - for(m = 0; m < 16; m++) if(pixelorder[m] == a) break; - for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1]; - pixelorder[0] = a; - - //calculate the real pixel order - for(m = 0; m < 16; m++) realorder[m] = pixelorder[m]; - - //rotate reference pixel c value to top - for(m = 0; m < 16; m++) if(realorder[m] == c) break; - for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; - realorder[0] = c; - - //rotate reference pixel b value to top - for(m = 0; m < 16; m++) if(realorder[m] == b) break; - for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; - realorder[0] = b; - - //rotate reference pixel a value to top - for(m = 0; m < 16; m++) if(realorder[m] == a) break; - for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; - realorder[0] = a; - - //get 4 symbols - for(unsigned bit = 0; bit < 4; bit++) { - //get prob - unsigned prob = probability(con); - - //get symbol - unsigned flag_lps; - if(val <= span - prob) { //mps - span = span - prob; - flag_lps = 0; - } else { //lps - val = val - (span - (prob - 1)); - span = prob - 1; - flag_lps = 1; - } - - //renormalize - unsigned shift = 0; - while(span < 0x7f) { - shift++; - - span = (span << 1) + 1; - val = (val << 1) + (in >> 7); - - in <<= 1; - if(--in_count == 0) { - in = datarom_read(dcu_addr++); - in_count = 8; - } - } - - //update processing info - lps = (lps << 1) + flag_lps; - unsigned invertbit = context[con].invert; - inverts = (inverts << 1) + invertbit; - - //update context state - if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; - if(flag_lps) context[con].index = next_lps(con); - else if(shift) context[con].index = next_mps(con); - - //get next context - con = context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); - } - - //get pixel - b = realorder[(lps ^ inverts) & 0x0f]; - out1 = (out1 << 4) + ((out0 >> 28) & 0x0f); - out0 = (out0 << 4) + b; - } - - //convert pixel data into bitplanes - unsigned data = deinterleave_4x8(out0); - dcu_tiledata[dcu_dp + row * 2 + 0] = data >> 24; - dcu_tiledata[dcu_dp + row * 2 + 1] = data >> 16; - dcu_tiledata[dcu_dp + row * 2 + 16] = data >> 8; - dcu_tiledata[dcu_dp + row * 2 + 17] = data >> 0; - } -} - -// +*/ +/* void SPC7110::deinterleave_1bpp(unsigned length) { uint8 *target = dcu_output, *source = dcu_tiledata; for(unsigned row = 0, sp = 0; row < 8; row++) { @@ -362,137 +80,4 @@ void SPC7110::deinterleave_4bpp(unsigned length) { sp = sp + 2 * length + 16 * ((sp + 2 * length) / 16 - sp / 16); } } - -// - -uint8 SPC7110::probability (unsigned n) { return evolution_table[context[n].index][0]; } -uint8 SPC7110::next_lps (unsigned n) { return evolution_table[context[n].index][1]; } -uint8 SPC7110::next_mps (unsigned n) { return evolution_table[context[n].index][2]; } -bool SPC7110::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; } - -unsigned SPC7110::deinterleave_2x8(unsigned data) { - //reverse morton lookup: de-interleave two 8-bit values - //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8 - //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0 - unsigned result = 0; - for(unsigned mask = 1u << 15; mask; mask >>= 2) result = (result << 1) | (bool)(data & mask); - for(unsigned mask = 1u << 14; mask; mask >>= 2) result = (result << 1) | (bool)(data & mask); - return result; -} - -unsigned SPC7110::deinterleave_4x8(unsigned data) { - //reverse morton lookup: de-interleave four 8-bit values - //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24 - //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16 - //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8 - //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0 - unsigned result = 0; - for(unsigned mask = 1u << 31; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask); - for(unsigned mask = 1u << 30; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask); - for(unsigned mask = 1u << 29; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask); - for(unsigned mask = 1u << 28; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask); - return result; -} - -const uint8 SPC7110::evolution_table[53][4] = { -//{prob, nextlps, nextmps, toggle invert}, - - {0x5a, 1, 1, 1}, - {0x25, 6, 2, 0}, - {0x11, 8, 3, 0}, - {0x08, 10, 4, 0}, - {0x03, 12, 5, 0}, - {0x01, 15, 5, 0}, - - {0x5a, 7, 7, 1}, - {0x3f, 19, 8, 0}, - {0x2c, 21, 9, 0}, - {0x20, 22, 10, 0}, - {0x17, 23, 11, 0}, - {0x11, 25, 12, 0}, - {0x0c, 26, 13, 0}, - {0x09, 28, 14, 0}, - {0x07, 29, 15, 0}, - {0x05, 31, 16, 0}, - {0x04, 32, 17, 0}, - {0x03, 34, 18, 0}, - {0x02, 35, 5, 0}, - - {0x5a, 20, 20, 1}, - {0x48, 39, 21, 0}, - {0x3a, 40, 22, 0}, - {0x2e, 42, 23, 0}, - {0x26, 44, 24, 0}, - {0x1f, 45, 25, 0}, - {0x19, 46, 26, 0}, - {0x15, 25, 27, 0}, - {0x11, 26, 28, 0}, - {0x0e, 26, 29, 0}, - {0x0b, 27, 30, 0}, - {0x09, 28, 31, 0}, - {0x08, 29, 32, 0}, - {0x07, 30, 33, 0}, - {0x05, 31, 34, 0}, - {0x04, 33, 35, 0}, - {0x04, 33, 36, 0}, - {0x03, 34, 37, 0}, - {0x02, 35, 38, 0}, - {0x02, 36, 5, 0}, - - {0x58, 39, 40, 1}, - {0x4d, 47, 41, 0}, - {0x43, 48, 42, 0}, - {0x3b, 49, 43, 0}, - {0x34, 50, 44, 0}, - {0x2e, 51, 45, 0}, - {0x29, 44, 46, 0}, - {0x25, 45, 24, 0}, - - {0x56, 47, 48, 1}, - {0x4f, 47, 49, 0}, - {0x47, 48, 50, 0}, - {0x41, 49, 51, 0}, - {0x3c, 50, 52, 0}, - {0x37, 51, 43, 0}, -}; - -const uint8 SPC7110::context_table[32][2] = { -//{next 0, next 1}, - - { 1, 2}, - - { 3, 8}, - {13, 14}, - - {15, 16}, - {17, 18}, - {19, 20}, - {21, 22}, - {23, 24}, - {25, 26}, - {25, 26}, - {25, 26}, - {25, 26}, - {25, 26}, - {27, 28}, - {29, 30}, - - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - {31, 31}, - - {31, 31}, -}; +*/ diff --git a/bsnes/sfc/chip/spc7110/decompressor.cpp b/bsnes/sfc/chip/spc7110/decompressor.cpp new file mode 100755 index 00000000..365dc5a2 --- /dev/null +++ b/bsnes/sfc/chip/spc7110/decompressor.cpp @@ -0,0 +1,218 @@ +//SPC7110 decompressor +//original implementation: neviksti +//optimized implementation: cydrak + +struct Decompressor { + SPC7110 &spc7110; + + Decompressor(SPC7110 &spc7110) : spc7110(spc7110) {} + + uint8 input() { + return spc7110.datarom_read(offset++); + } + + uint8 output() { + if(cursor == 0) decompress(); + uint8 data = tile[cursor++]; + cursor &= 8 * bpp - 1; + return data; + } + + uint32 deinterleave(uint64 data, unsigned bits) { + data = data & (1ull << bits) - 1; + data = 0x5555555555555555ull & (data << bits | data >> 1); + data = 0x3333333333333333ull & (data | data >> 1); + data = 0x0f0f0f0f0f0f0f0full & (data | data >> 2); + data = 0x00ff00ff00ff00ffull & (data | data >> 4); + data = 0x0000ffff0000ffffull & (data | data >> 8); + return data | data >> 16; + } + + uint64 moveToFront(uint64 list, unsigned nibble) { + for(uint64 n = 0, mask = ~15; n < 64; n += 4, mask <<= 4) { + if((list >> n & 15) != nibble) continue; + return list = (list & mask) + (list << 4 & ~mask) + nibble; + } + return list; + } + + void initialize(unsigned mode, unsigned origin) { + for(auto &root : context) for(auto &node : root) node = {0, 0}; + base = 0; + range = Max + 1; + bpp = 1 << mode; + offset = origin; + cursor = 0; + bits = 8; + read = input(); + read = read << 8 | input(); + write = 0; + pixels = 0; + colormap = 0xfedcba9876543210ull; + } + + void decompress() { + for(unsigned row = 0; row < 8; row++) { + for(unsigned pixel = 0; pixel < 8; pixel++) { + uint64 map = colormap; + unsigned diff = 0; + + if(bpp > 1) { + unsigned pa = (bpp == 2 ? pixels >> 2 & 3 : pixels >> 0 & 15); + unsigned pb = (bpp == 2 ? pixels >> 14 & 3 : pixels >> 28 & 15); + unsigned pc = (bpp == 2 ? pixels >> 16 & 3 : pixels >> 32 & 15); + + if(pa != pb || pb != pc) { + unsigned match = pa ^ pb ^ pc; + diff = 4; + if((match ^ pc) == 0) diff = 3; + if((match ^ pb) == 0) diff = 2; + if((match ^ pa) == 0) diff = 1; + } + + colormap = moveToFront(colormap, pa); + + map = moveToFront(map, pc); + map = moveToFront(map, pb); + map = moveToFront(map, pa); + } + + for(unsigned plane = 0; plane < bpp; plane++) { + unsigned bit = bpp > 1 ? 1 << plane : 1 << (pixel & 3); + unsigned history = bit - 1 & write; + unsigned set = 0; + + if(bpp == 1) set = pixel >= 4; + if(bpp == 2) set = diff; + if(plane >= 2 && history <= 1) set = diff; + + auto &ctx = context[set][bit + history - 1]; + auto &model = evolution[ctx.prediction]; + uint8 lps_offset = range - model.probability; + bool symbol = read >= (lps_offset << 8); + + write = write << 1 | (symbol ^ ctx.swap); + + if(symbol == MPS) { + range = lps_offset; + } else { + range -= lps_offset; + read -= lps_offset << 8; + base += lps_offset; + } + + while(range <= Max / 2) { + ctx.prediction = model.next[symbol]; + + range <<= 1; + read <<= 1; + base <<= 1; + + if(--bits == 0) { + bits = 8; + read += input(); + } + } + + if(symbol == LPS && model.probability > Half) ctx.swap ^= 1; + } + + unsigned index = write & (1 << bpp) - 1; + if(bpp == 1) index ^= pixels >> 15 & 1; + + pixels = pixels << bpp | (map >> 4 * index & 15); + } + + if(bpp == 1) { + tile[row] = pixels; + } + + if(bpp == 2) { + uint32 slice = deinterleave(pixels, 16); + tile[row * 2 + 0] = slice >> 0; + tile[row * 2 + 1] = slice >> 8; + } + + if(bpp == 4) { + uint32 slice = deinterleave(deinterleave(pixels, 32), 32); + tile[row * 2 + 0x00] = slice >> 0; + tile[row * 2 + 0x01] = slice >> 8; + tile[row * 2 + 0x10] = slice >> 16; + tile[row * 2 + 0x11] = slice >> 24; + } + } + } + + void serialize(serializer &s) { + for(auto &root : context) { + for(auto &node : root) { + s.integer(node.prediction); + s.integer(node.swap); + } + } + + s.integer(base); + s.integer(range); + s.integer(bpp); + s.integer(offset); + s.integer(cursor); + s.integer(bits); + s.integer(read); + s.integer(write); + s.integer(pixels); + s.integer(colormap); + s.array(tile); + } + + enum : unsigned { MPS = 0, LPS = 1 }; + enum : unsigned { One = 0xaa, Half = 0x55, Max = 0xff }; + + struct ModelState { + uint8 probability; + uint8 next[2]; + }; + static ModelState evolution[53]; + + struct Context { + uint8 prediction; + uint8 swap; + } context[5][15]; + + uint8 base; + uint16 range; + unsigned bpp; + unsigned offset; + unsigned cursor; + unsigned bits; + uint16 read; + uint8 write; + uint64 pixels; + uint64 colormap; + uint8 tile[32]; +}; + +Decompressor::ModelState Decompressor::evolution[53] = { + {0x5a, { 1, 1}}, {0x25, { 2, 6}}, {0x11, { 3, 8}}, + {0x08, { 4,10}}, {0x03, { 5,12}}, {0x01, { 5,15}}, + + {0x5a, { 7, 7}}, {0x3f, { 8,19}}, {0x2c, { 9,21}}, + {0x20, {10,22}}, {0x17, {11,23}}, {0x11, {12,25}}, + {0x0c, {13,26}}, {0x09, {14,28}}, {0x07, {15,29}}, + {0x05, {16,31}}, {0x04, {17,32}}, {0x03, {18,34}}, + {0x02, { 5,35}}, + + {0x5a, {20,20}}, {0x48, {21,39}}, {0x3a, {22,40}}, + {0x2e, {23,42}}, {0x26, {24,44}}, {0x1f, {25,45}}, + {0x19, {26,46}}, {0x15, {27,25}}, {0x11, {28,26}}, + {0x0e, {29,26}}, {0x0b, {30,27}}, {0x09, {31,28}}, + {0x08, {32,29}}, {0x07, {33,30}}, {0x05, {34,31}}, + {0x04, {35,33}}, {0x04, {36,33}}, {0x03, {37,34}}, + {0x02, {38,35}}, {0x02, { 5,36}}, + + {0x58, {40,39}}, {0x4d, {41,47}}, {0x43, {42,48}}, + {0x3b, {43,49}}, {0x34, {44,50}}, {0x2e, {45,51}}, + {0x29, {46,44}}, {0x25, {24,45}}, + + {0x56, {48,47}}, {0x4f, {49,47}}, {0x47, {50,48}}, + {0x41, {51,49}}, {0x3c, {52,50}}, {0x37, {43,51}}, +}; diff --git a/bsnes/sfc/chip/spc7110/serialization.cpp b/bsnes/sfc/chip/spc7110/serialization.cpp index 33e4fc31..10916846 100755 --- a/bsnes/sfc/chip/spc7110/serialization.cpp +++ b/bsnes/sfc/chip/spc7110/serialization.cpp @@ -13,17 +13,10 @@ void SPC7110::serialize(serializer &s) { s.integer(r480b); s.integer(r480c); + s.integer(dcu_pending); s.integer(dcu_mode); s.integer(dcu_addr); - s.integer(dcu_sp); - s.integer(dcu_dp); - - s.array(dcu_output); - - for(auto &ctx : context) { - s.integer(ctx.index); - s.integer(ctx.invert); - } + decompressor->serialize(s); s.integer(r4810); s.integer(r4811); @@ -53,8 +46,8 @@ void SPC7110::serialize(serializer &s) { s.integer(r482e); s.integer(r482f); - s.integer(mul_wait); - s.integer(div_wait); + s.integer(mul_pending); + s.integer(div_pending); s.integer(r4830); s.integer(r4831); diff --git a/bsnes/sfc/chip/spc7110/spc7110.cpp b/bsnes/sfc/chip/spc7110/spc7110.cpp index 22dd357d..ec6e71f2 100755 --- a/bsnes/sfc/chip/spc7110/spc7110.cpp +++ b/bsnes/sfc/chip/spc7110/spc7110.cpp @@ -9,6 +9,14 @@ namespace SuperFamicom { #include "serialization.cpp" SPC7110 spc7110; +SPC7110::SPC7110() { + decompressor = new Decompressor(*this); +} + +SPC7110::~SPC7110() { + delete decompressor; +} + void SPC7110::Enter() { spc7110.enter(); } void SPC7110::enter() { @@ -17,14 +25,19 @@ void SPC7110::enter() { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } - if(mul_wait) { if(--mul_wait == 0) alu_multiply(); } - if(div_wait) { if(--div_wait == 0) alu_divide(); } + if(dcu_pending) { dcu_pending = 0; dcu_begin_transfer(); } + if(mul_pending) { mul_pending = 0; alu_multiply(); } + if(div_pending) { div_pending = 0; alu_divide(); } - step(1); - synchronize_cpu(); + add_clocks(1); } } +void SPC7110::add_clocks(unsigned clocks) { + step(clocks); + synchronize_cpu(); +} + void SPC7110::init() { } @@ -38,7 +51,7 @@ void SPC7110::power() { } void SPC7110::reset() { - create(SPC7110::Enter, 32768 * 128); + create(SPC7110::Enter, 21477272); r4801 = 0x00; r4802 = 0x00; @@ -52,10 +65,9 @@ void SPC7110::reset() { r480b = 0x00; r480c = 0x00; + dcu_pending = 0; dcu_mode = 0; dcu_addr = 0; - dcu_sp = 0; - dcu_dp = 0; r4810 = 0x00; r4811 = 0x00; @@ -85,8 +97,8 @@ void SPC7110::reset() { r482e = 0x00; r482f = 0x00; - mul_wait = 0; - div_wait = 0; + mul_pending = 0; + div_pending = 0; r4830 = 0x00; r4831 = 0x00; @@ -123,11 +135,7 @@ uint8 SPC7110::mmio_read(unsigned addr) { case 0x4809: return r4809; case 0x480a: return r480a; case 0x480b: return r480b; - case 0x480c: { - uint8 status = r480c; - r480c &= 0x7f; - return status; - } + case 0x480c: return r480c; //============== //data port unit @@ -136,7 +144,6 @@ uint8 SPC7110::mmio_read(unsigned addr) { case 0x4810: { uint8 data = r4810; data_port_increment_4810(); - data_port_read(); return data; } case 0x4811: return r4811; @@ -200,10 +207,10 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) { case 0x4801: r4801 = data; break; case 0x4802: r4802 = data; break; - case 0x4803: r4803 = data & 0x7f; break; + case 0x4803: r4803 = data; break; case 0x4804: r4804 = data; dcu_load_address(); break; case 0x4805: r4805 = data; break; - case 0x4806: r4806 = data; dcu_begin_transfer(); break; + case 0x4806: r4806 = data; r480c &= 0x7f; dcu_pending = 1; break; case 0x4807: r4807 = data; break; case 0x4808: break; case 0x4809: r4809 = data; break; @@ -216,9 +223,9 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) { case 0x4811: r4811 = data; break; case 0x4812: r4812 = data; break; - case 0x4813: r4813 = data & 0x7f; data_port_read(); break; + case 0x4813: r4813 = data; data_port_read(); break; case 0x4814: r4814 = data; data_port_increment_4814(); break; - case 0x4815: r4815 = data; data_port_increment_4815(); break; + case 0x4815: r4815 = data; if(r4818 & 2) data_port_read(); data_port_increment_4815(); break; case 0x4816: r4816 = data; break; case 0x4817: r4817 = data; break; case 0x4818: r4818 = data & 0x7f; data_port_read(); break; @@ -232,9 +239,9 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) { case 0x4822: r4822 = data; break; case 0x4823: r4823 = data; break; case 0x4824: r4824 = data; break; - case 0x4825: r4825 = data; r482f |= 0x81; mul_wait = mul_delay; break; + case 0x4825: r4825 = data; r482f |= 0x81; mul_pending = 1; break; case 0x4826: r4826 = data; break; - case 0x4827: r4827 = data; r482f |= 0x80; div_wait = div_delay; break; + case 0x4827: r4827 = data; r482f |= 0x80; div_pending = 1; break; case 0x482e: r482e = data & 0x01; break; //=================== @@ -250,9 +257,6 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) { } } -SPC7110::SPC7110() { -} - //============ //SPC7110::DCU //============ diff --git a/bsnes/sfc/chip/spc7110/spc7110.hpp b/bsnes/sfc/chip/spc7110/spc7110.hpp index ea4c7153..f0dc8617 100755 --- a/bsnes/sfc/chip/spc7110/spc7110.hpp +++ b/bsnes/sfc/chip/spc7110/spc7110.hpp @@ -1,15 +1,9 @@ +struct Decompressor; + struct SPC7110 : Coprocessor { unsigned prom_base, prom_size; //program ROM unsigned drom_base, drom_size; //data ROM - uint4 rtcram[16]; - - enum : unsigned { - mul_delay = 6, - div_delay = 8, - rtc_delay = 20, - }; - static void Enter(); void enter(); void init(); @@ -18,6 +12,8 @@ struct SPC7110 : Coprocessor { void power(); void reset(); + void add_clocks(unsigned clocks); + uint8 mmio_read(unsigned addr); void mmio_write(unsigned addr, uint8 data); @@ -32,28 +28,17 @@ struct SPC7110 : Coprocessor { void serialize(serializer&); SPC7110(); + ~SPC7110(); //dcu.cpp void dcu_load_address(); void dcu_begin_transfer(); uint8 dcu_read(); - void decompress_1bpp(bool init = false); - void decompress_2bpp(bool init = false); - void decompress_4bpp(bool init = false); - void deinterleave_1bpp(unsigned length); void deinterleave_2bpp(unsigned length); void deinterleave_4bpp(unsigned length); - uint8 probability(unsigned n); - uint8 next_lps(unsigned n); - uint8 next_mps(unsigned n); - bool toggle_invert(unsigned n); - - unsigned deinterleave_2x8(unsigned data); - unsigned deinterleave_4x8(unsigned data); - //data.cpp uint8 datarom_read(unsigned addr); @@ -81,7 +66,7 @@ private: //================== uint8 r4801; //compression table B0 uint8 r4802; //compression table B1 - uint8 r4803; //compression table B2 + uint7 r4803; //compression table B2 uint8 r4804; //compression table index uint8 r4805; //decompression buffer index B0 uint8 r4806; //decompression buffer index B1 @@ -91,21 +76,10 @@ private: uint8 r480b; //decompression settings uint8 r480c; //decompression status + bool dcu_pending; uint2 dcu_mode; uint23 dcu_addr; - unsigned dcu_sp; - unsigned dcu_dp; - - uint8 dcu_output[32]; - uint8 dcu_tiledata[256 * 32]; - - struct ContextState { - uint8 index; - uint8 invert; - } context[32]; - - static const uint8 evolution_table[53][4]; - static const uint8 context_table[32][2]; + Decompressor *decompressor; //============== //data port unit @@ -113,7 +87,7 @@ private: uint8 r4810; //data port read + seek uint8 r4811; //data offset B0 uint8 r4812; //data offset B1 - uint8 r4813; //data offset B2 + uint7 r4813; //data offset B2 uint8 r4814; //data adjust B0 uint8 r4815; //data adjust B1 uint8 r4816; //data stride B0 @@ -141,8 +115,8 @@ private: uint8 r482e; //math settings uint8 r482f; //math status - unsigned mul_wait; - unsigned div_wait; + bool mul_pending; + bool div_pending; //=================== //memory control unit diff --git a/bsnes/target-ethos/ethos.cpp b/bsnes/target-ethos/ethos.cpp index 555cd550..379f87dc 100755 --- a/bsnes/target-ethos/ethos.cpp +++ b/bsnes/target-ethos/ethos.cpp @@ -9,6 +9,10 @@ Emulator::Interface& system() { return *application->active; } +bool Application::focused() { + return config->input.focusAllow || presentation->focused(); +} + string Application::path(const string &filename) { string path = {basepath, filename}; if(file::exists(path)) return path; diff --git a/bsnes/target-ethos/ethos.hpp b/bsnes/target-ethos/ethos.hpp index 51e46416..e0581957 100755 --- a/bsnes/target-ethos/ethos.hpp +++ b/bsnes/target-ethos/ethos.hpp @@ -45,6 +45,7 @@ struct Application { string titleFont; string monospaceFont; + bool focused(); string path(const string &filename); void commandLineLoad(string pathname); void run(); diff --git a/bsnes/target-ethos/input/input.cpp b/bsnes/target-ethos/input/input.cpp index 365565b5..31d4179d 100755 --- a/bsnes/target-ethos/input/input.cpp +++ b/bsnes/target-ethos/input/input.cpp @@ -78,6 +78,7 @@ bool DigitalInput::bind(unsigned scancode, int16_t value) { } int16_t DigitalInput::poll() { + if(application->focused() == false) return 0; bool result = logic; for(auto &item : inputList) { @@ -121,6 +122,7 @@ bool RelativeInput::bind(unsigned scancode, int16_t value) { } int16_t RelativeInput::poll() { + if(application->focused() == false) return 0; int16_t result = 0; for(auto &item : inputList) { @@ -160,6 +162,7 @@ bool AbsoluteInput::bind(unsigned scancode, int16_t value) { } int16_t AbsoluteInput::poll() { + if(application->focused() == false) return -32768; int16_t result = -32768; //offscreen value using nall::Mouse; diff --git a/bsnes/target-ethos/interface/interface.cpp b/bsnes/target-ethos/interface/interface.cpp index 9b8ecc62..30ccb9c3 100755 --- a/bsnes/target-ethos/interface/interface.cpp +++ b/bsnes/target-ethos/interface/interface.cpp @@ -103,7 +103,6 @@ void Interface::audioSample(int16_t lsample, int16_t rsample) { } int16_t Interface::inputPoll(unsigned port, unsigned device, unsigned input) { - if(config->input.focusAllow == false && presentation->focused() == false) return 0; unsigned guid = system().port[port].device[device].input[input].guid; return inputManager->inputMap[guid]->poll(); }