From 0611fefefa89fbe0b662bbd798da680c919924fd Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 19 May 2012 16:28:54 +1000 Subject: [PATCH] Update to v089r04 release. byuu says: Changelog: (SPC7110) - emulated $480b.d0 + $4807 deinterleave mode - cleaned up decompression core (I'd still like to wipe out those static variables, those are bad for save states.) - improved emulation of data port ($481a only increments, never reads) - improved emulation of RTC (block appropriate bits in the hour register based on 12/24h mode select; $4840 modes != 1 all disable the chip; added MDR; etc.) --- bsnes/emulator/emulator.hpp | 2 +- bsnes/sfc/chip/spc7110/data.cpp | 16 +- .../sfc/chip/spc7110/{decomp.cpp => dcu.cpp} | 260 +++++++++--------- bsnes/sfc/chip/spc7110/decomp.hpp | 43 --- bsnes/sfc/chip/spc7110/rtc.cpp | 5 +- bsnes/sfc/chip/spc7110/serialization.cpp | 29 +- bsnes/sfc/chip/spc7110/spc7110.cpp | 64 ++--- bsnes/sfc/chip/spc7110/spc7110.hpp | 54 +++- 8 files changed, 220 insertions(+), 253 deletions(-) rename bsnes/sfc/chip/spc7110/{decomp.cpp => dcu.cpp} (72%) delete mode 100755 bsnes/sfc/chip/spc7110/decomp.hpp diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index 93629602..1af327b7 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.03"; + static const char Version[] = "089.04"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; } diff --git a/bsnes/sfc/chip/spc7110/data.cpp b/bsnes/sfc/chip/spc7110/data.cpp index 569d7def..1d07a9b5 100755 --- a/bsnes/sfc/chip/spc7110/data.cpp +++ b/bsnes/sfc/chip/spc7110/data.cpp @@ -18,7 +18,7 @@ unsigned SPC7110::data_increment() { return r4816 | r4817 << 8; } void SPC7110::set_data_offset(unsigned addr) { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; } void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; } -void SPC7110::data_port_read_a() { +void SPC7110::data_port_read() { unsigned offset = data_offset(); unsigned adjust = data_adjust(); if(r4818 & 8) adjust = (int16)adjust; @@ -26,18 +26,6 @@ void SPC7110::data_port_read_a() { r4810 = datarom_read(offset); } -void SPC7110::data_port_read_b() { - unsigned offset = data_offset(); - unsigned adjust = data_adjust(); - if(r4818 & 8) adjust = (int16)adjust; - r481a = datarom_read(offset + adjust); -} - -void SPC7110::data_port_read() { - data_port_read_a(); - data_port_read_b(); -} - void SPC7110::data_port_increment_a() { unsigned adjust = data_adjust(); if(r4818 & 8) adjust = (int16)adjust; @@ -61,7 +49,7 @@ void SPC7110::data_port_increment_b() { if((r4818 & 16) != 0) set_data_adjust(adjust + adjust); } -void SPC7110::data_port_increment() { +void SPC7110::data_port_increment_c() { if((r4818 & 2) == 0) return; if(r4818 & 16) return; diff --git a/bsnes/sfc/chip/spc7110/decomp.cpp b/bsnes/sfc/chip/spc7110/dcu.cpp similarity index 72% rename from bsnes/sfc/chip/spc7110/decomp.cpp rename to bsnes/sfc/chip/spc7110/dcu.cpp index c04c2f09..e6342a3e 100755 --- a/bsnes/sfc/chip/spc7110/decomp.cpp +++ b/bsnes/sfc/chip/spc7110/dcu.cpp @@ -1,72 +1,72 @@ -#ifdef SPC7110_CPP +void SPC7110::dcu_load_address() { + unsigned table = r4801 | r4802 << 8 | r4803 << 16; + unsigned index = r4804 << 2; -uint8 SPC7110::Decomp::read() { - if(decomp_buffer_length == 0) { - //decompress at least (decomp_buffer_size / 2) bytes to the buffer - switch(decomp_mode) { - case 0: mode0(false); break; - case 1: mode1(false); break; - case 2: mode2(false); break; - default: return 0x00; + unsigned addr = table + index; + dcu_mode = datarom_read(addr + 0); + dcu_addr = datarom_read(addr + 1) << 16; + dcu_addr |= datarom_read(addr + 2) << 8; + dcu_addr |= datarom_read(addr + 3) << 0; +} + +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; + } + + r480c |= 0x80; + dcu_sp = 0; + + //reset context states + for(auto &ctx : context) { + ctx.index = 0; + ctx.invert = 0; + } + + unsigned seek = (r4805 | r4806 << 8) << dcu_mode; + while(seek--) dcu_read(); +} + +uint8 SPC7110::dcu_read() { + unsigned tilesize = 8 << dcu_mode; + + if(dcu_sp == 0) { + unsigned tiles = r480b & 1 ? r4807 : 1; + for(unsigned tile = 0; tile < tiles; tile++) { + dcu_dp = tile * tilesize; + switch(dcu_mode) { + case 0: decompress_1bpp(); deinterleave_1bpp(tiles); break; + case 1: decompress_2bpp(); deinterleave_2bpp(tiles); break; + case 2: decompress_4bpp(); deinterleave_4bpp(tiles); break; + case 3: return 0x00; + } } } - uint8 data = decomp_buffer[decomp_buffer_rdoffset++]; - decomp_buffer_rdoffset &= decomp_buffer_size - 1; - decomp_buffer_length--; + uint8 data = dcu_output[dcu_sp++]; + dcu_sp &= tilesize - 1; return data; } -void SPC7110::Decomp::write(uint8 data) { - decomp_buffer[decomp_buffer_wroffset++] = data; - decomp_buffer_wroffset &= decomp_buffer_size - 1; - decomp_buffer_length++; -} - -uint8 SPC7110::Decomp::dataread() { - return spc7110.datarom_read(decomp_offset++); -} - -void SPC7110::Decomp::init(unsigned mode, unsigned offset, unsigned index) { - decomp_mode = mode; - decomp_offset = offset; - - decomp_buffer_rdoffset = 0; - decomp_buffer_wroffset = 0; - decomp_buffer_length = 0; - - //reset context states - for(unsigned i = 0; i < 32; i++) { - context[i].index = 0; - context[i].invert = 0; - } - - switch(decomp_mode) { - case 0: mode0(true); break; - case 1: mode1(true); break; - case 2: mode2(true); break; - } - - //decompress up to requested output data index - while(index--) read(); -} - // -void SPC7110::Decomp::mode0(bool init) { +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 = dataread(); - in = dataread(); + val = datarom_read(dcu_addr++); + in = datarom_read(dcu_addr++); in_count = 8; return; } - while(decomp_buffer_length < (decomp_buffer_size >> 1)) { + for(unsigned row = 0; row < 8; row++) { for(unsigned bit = 0; bit < 8; bit++) { //get context uint8 mask = (1 << (bit & 3)) - 1; @@ -100,7 +100,7 @@ void SPC7110::Decomp::mode0(bool init) { in <<= 1; if(--in_count == 0) { - in = dataread(); + in = datarom_read(dcu_addr++); in_count = 8; } } @@ -116,11 +116,11 @@ void SPC7110::Decomp::mode0(bool init) { } //save byte - write(out); + dcu_tiledata[dcu_dp + row] = out; } } -void SPC7110::Decomp::mode1(bool init) { +void SPC7110::decompress_2bpp(bool init) { static int pixelorder[4], realorder[4]; static uint8 in, val, span; static int out, inverts, lps, in_count; @@ -129,13 +129,13 @@ void SPC7110::Decomp::mode1(bool init) { for(unsigned i = 0; i < 4; i++) pixelorder[i] = i; out = inverts = lps = 0; span = 0xff; - val = dataread(); - in = dataread(); + val = datarom_read(dcu_addr++); + in = datarom_read(dcu_addr++); in_count = 8; return; } - while(decomp_buffer_length < (decomp_buffer_size >> 1)) { + for(unsigned row = 0; row < 8; row++) { for(unsigned pixel = 0; pixel < 8; pixel++) { //get first symbol context unsigned a = ((out >> (1 * 2)) & 3); @@ -193,7 +193,7 @@ void SPC7110::Decomp::mode1(bool init) { in <<= 1; if(--in_count == 0) { - in = dataread(); + in = datarom_read(dcu_addr++); in_count = 8; } } @@ -218,29 +218,27 @@ void SPC7110::Decomp::mode1(bool init) { //turn pixel data into bitplanes unsigned data = deinterleave_2x8(out); - write(data >> 8); - write(data >> 0); + dcu_tiledata[dcu_dp + row * 2 + 0] = data >> 8; + dcu_tiledata[dcu_dp + row * 2 + 1] = data >> 0; } } -void SPC7110::Decomp::mode2(bool init) { +void SPC7110::decompress_4bpp(bool init) { static int pixelorder[16], realorder[16]; - static uint8 bitplanebuffer[16], buffer_index; 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; - buffer_index = 0; out0 = out1 = inverts = lps = 0; span = 0xff; - val = dataread(); - in = dataread(); + val = datarom_read(dcu_addr++); + in = datarom_read(dcu_addr++); in_count = 8; return; } - while(decomp_buffer_length < (decomp_buffer_size >> 1)) { + for(unsigned row = 0; row < 8; row++) { for(unsigned pixel = 0; pixel < 8; pixel++) { //get first symbol context unsigned a = ((out0 >> (0 * 4)) & 15); @@ -299,7 +297,7 @@ void SPC7110::Decomp::mode2(bool init) { in <<= 1; if(--in_count == 0) { - in = dataread(); + in = datarom_read(dcu_addr++); in_count = 8; } } @@ -315,7 +313,7 @@ void SPC7110::Decomp::mode2(bool init) { else if(shift) context[con].index = next_mps(con); //get next context - con = mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); + con = context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); } //get pixel @@ -326,21 +324,75 @@ void SPC7110::Decomp::mode2(bool init) { //convert pixel data into bitplanes unsigned data = deinterleave_4x8(out0); - write(data >> 24); - write(data >> 16); - bitplanebuffer[buffer_index++] = data >> 8; - bitplanebuffer[buffer_index++] = data >> 0; - - if(buffer_index == 16) { - for(unsigned i = 0; i < 16; i++) write(bitplanebuffer[i]); - buffer_index = 0; - } + 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; } } // -const uint8 SPC7110::Decomp::evolution_table[53][4] = { +void SPC7110::deinterleave_1bpp(unsigned length) { + uint8 *target = dcu_output, *source = dcu_tiledata; + for(unsigned row = 0, sp = 0; row < 8; row++) { + target[row] = source[sp]; + sp += length; + } +} + +void SPC7110::deinterleave_2bpp(unsigned length) { + uint8 *target = dcu_output, *source = dcu_tiledata; + for(unsigned row = 0, sp = 0; row < 8; row++) { + target[row * 2 + 0] = source[sp + 0]; + target[row * 2 + 1] = source[sp + 1]; + sp += 2 * length; + } +} + +void SPC7110::deinterleave_4bpp(unsigned length) { + uint8 *target = dcu_output, *source = dcu_tiledata; + for(unsigned row = 0, sp = 0; row < 8; row++) { + target[row * 2 + 0] = source[sp + 0]; + target[row * 2 + 1] = source[sp + 1]; + target[row * 2 + 16] = source[sp + 16]; + target[row * 2 + 17] = source[sp + 17]; + 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}, @@ -402,7 +454,7 @@ const uint8 SPC7110::Decomp::evolution_table[53][4] = { {0x37, 51, 43, 0}, }; -const uint8 SPC7110::Decomp::mode2_context_table[32][2] = { +const uint8 SPC7110::context_table[32][2] = { //{next 0, next 1}, { 1, 2}, @@ -442,55 +494,3 @@ const uint8 SPC7110::Decomp::mode2_context_table[32][2] = { {31, 31}, }; - -uint8 SPC7110::Decomp::probability (unsigned n) { return evolution_table[context[n].index][0]; } -uint8 SPC7110::Decomp::next_lps (unsigned n) { return evolution_table[context[n].index][1]; } -uint8 SPC7110::Decomp::next_mps (unsigned n) { return evolution_table[context[n].index][2]; } -bool SPC7110::Decomp::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; } - -unsigned SPC7110::Decomp::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::Decomp::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; -} - -// - -void SPC7110::Decomp::reset() { - //mode 3 is invalid; this is treated as a special case to always return 0x00 - //set to mode 3 so that reading decomp port before starting first decomp will return 0x00 - decomp_mode = 3; - - decomp_buffer_rdoffset = 0; - decomp_buffer_wroffset = 0; - decomp_buffer_length = 0; -} - -SPC7110::Decomp::Decomp() { - decomp_buffer = new uint8_t[decomp_buffer_size]; - reset(); -} - -SPC7110::Decomp::~Decomp() { - delete[] decomp_buffer; -} - -#endif diff --git a/bsnes/sfc/chip/spc7110/decomp.hpp b/bsnes/sfc/chip/spc7110/decomp.hpp deleted file mode 100755 index d12553d9..00000000 --- a/bsnes/sfc/chip/spc7110/decomp.hpp +++ /dev/null @@ -1,43 +0,0 @@ -struct Decomp { - uint8 read(); - void init(unsigned mode, unsigned offset, unsigned index); - void reset(); - - void serialize(serializer&); - Decomp(); - ~Decomp(); - -private: - unsigned decomp_mode; - unsigned decomp_offset; - - //read() will spool chunks half the size of decomp_buffer_size - enum { decomp_buffer_size = 64 }; //must be >= 64, and must be a power of two - uint8 *decomp_buffer; - unsigned decomp_buffer_rdoffset; - unsigned decomp_buffer_wroffset; - unsigned decomp_buffer_length; - - void write(uint8 data); - uint8 dataread(); - - void mode0(bool init); - void mode1(bool init); - void mode2(bool init); - - static const uint8 evolution_table[53][4]; - static const uint8 mode2_context_table[32][2]; - - struct ContextState { - uint8 index; - uint8 invert; - } context[32]; - - 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); -}; diff --git a/bsnes/sfc/chip/spc7110/rtc.cpp b/bsnes/sfc/chip/spc7110/rtc.cpp index fefc12ff..5386137b 100755 --- a/bsnes/sfc/chip/spc7110/rtc.cpp +++ b/bsnes/sfc/chip/spc7110/rtc.cpp @@ -78,7 +78,10 @@ void SPC7110::rtc_write(uint4 addr, uint4 data) { case 0x2: rtcram[0x2] = data; break; case 0x3: rtcram[0x3] = data; break; case 0x4: rtcram[0x4] = data; break; - case 0x5: rtcram[0x5] = data; break; + case 0x5: + if((rtcram[0xf] & 4) == 0) rtcram[0x5] = data & ~2; //12-hour mode cannot set D5 + if((rtcram[0xf] & 4) != 0) rtcram[0x5] = data & ~4; //24-hour mode cannot set AM/PM + break; case 0x6: rtcram[0x6] = data; break; case 0x7: rtcram[0x7] = data; break; case 0x8: rtcram[0x8] = data; break; diff --git a/bsnes/sfc/chip/spc7110/serialization.cpp b/bsnes/sfc/chip/spc7110/serialization.cpp index 6b07287a..3aee8f6e 100755 --- a/bsnes/sfc/chip/spc7110/serialization.cpp +++ b/bsnes/sfc/chip/spc7110/serialization.cpp @@ -1,20 +1,5 @@ #ifdef SPC7110_CPP -void SPC7110::Decomp::serialize(serializer &s) { - s.integer(decomp_mode); - s.integer(decomp_offset); - - s.array(decomp_buffer, decomp_buffer_size); - s.integer(decomp_buffer_rdoffset); - s.integer(decomp_buffer_wroffset); - s.integer(decomp_buffer_length); - - for(unsigned n = 0; n < 32; n++) { - s.integer(context[n].index); - s.integer(context[n].invert); - } -} - void SPC7110::serialize(serializer &s) { for(auto &byte : rtcram) s.integer(byte); @@ -25,13 +10,22 @@ void SPC7110::serialize(serializer &s) { s.integer(r4805); s.integer(r4806); s.integer(r4807); - s.integer(r4808); s.integer(r4809); s.integer(r480a); s.integer(r480b); s.integer(r480c); - decomp.serialize(s); + 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); + } s.integer(r4810); s.integer(r4811); @@ -82,6 +76,7 @@ void SPC7110::serialize(serializer &s) { s.integer(rtc_mode); s.integer(rtc_addr); s.integer(rtc_wait); + s.integer(rtc_mdr); } #endif diff --git a/bsnes/sfc/chip/spc7110/spc7110.cpp b/bsnes/sfc/chip/spc7110/spc7110.cpp index ce6bc456..8872ec89 100755 --- a/bsnes/sfc/chip/spc7110/spc7110.cpp +++ b/bsnes/sfc/chip/spc7110/spc7110.cpp @@ -3,7 +3,7 @@ #define SPC7110_CPP namespace SuperFamicom { -#include "decomp.cpp" +#include "dcu.cpp" #include "data.cpp" #include "alu.cpp" #include "rtc.cpp" @@ -20,7 +20,7 @@ void SPC7110::enter() { if(mul_wait) { if(--mul_wait == 0) alu_multiply(); } if(div_wait) { if(--div_wait == 0) alu_divide(); } - if(rtc_wait) { if(--rtc_wait == 0) r4842 &= 0x7f; } + if(rtc_wait) { if(--rtc_wait == 0) r4842 |= 0x80; } rtc_clocks++; if((rtc_clocks & 0x7fff) == 0) rtc_duty(); //1/128th second @@ -65,13 +65,15 @@ void SPC7110::reset() { r4805 = 0x00; r4806 = 0x00; r4807 = 0x00; - r4808 = 0x00; r4809 = 0x00; r480a = 0x00; r480b = 0x00; r480c = 0x00; - decomp.reset(); + dcu_mode = 0; + dcu_addr = 0; + dcu_sp = 0; + dcu_dp = 0; r4810 = 0x00; r4811 = 0x00; @@ -122,6 +124,7 @@ void SPC7110::reset() { rtc_mode = 0; rtc_addr = 0; rtc_wait = 0; + rtc_mdr = 0; } uint8 SPC7110::mmio_read(unsigned addr) { @@ -137,9 +140,9 @@ uint8 SPC7110::mmio_read(unsigned addr) { case 0x4800: { uint16 counter = r4809 | r480a << 8; counter--; - r4809 = counter; + r4809 = counter >> 0; r480a = counter >> 8; - return decomp.read(); + return dcu_read(); } case 0x4801: return r4801; case 0x4802: return r4802; @@ -165,7 +168,7 @@ uint8 SPC7110::mmio_read(unsigned addr) { case 0x4810: { uint8 data = r4810; data_port_increment_a(); - data_port_read_a(); + data_port_read(); return data; } case 0x4811: return r4811; @@ -177,10 +180,8 @@ uint8 SPC7110::mmio_read(unsigned addr) { case 0x4817: return r4817; case 0x4818: return r4818; case 0x481a: { - uint8 data = r481a; data_port_increment_b(); - data_port_read_b(); - return data; + return 0x00; } //========= @@ -220,8 +221,11 @@ uint8 SPC7110::mmio_read(unsigned addr) { case 0x4840: return r4840; case 0x4841: { - if((r4840 & 1) == 0) return 0x00; //RTC disabled? - if(rtc_mode != 2) return 0x00; + if(r4840 != 1) return 0x00; //RTC disabled? + if(r4842 == 0) return 0x00; //RTC busy? + if(rtc_mode != 2) return 0x00; //waiting for command or address? + if(r4841 == 0x03) return rtc_mdr; //in write mode? + if(r4841 != 0x0c) return 0x00; //not in read mode? r4842 |= 0x80; rtc_wait = rtc_delay; return rtc_read(rtc_addr++); @@ -246,22 +250,9 @@ 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 0x4804: r4804 = data; break; + case 0x4804: r4804 = data; dcu_load_address(); break; case 0x4805: r4805 = data; break; - case 0x4806: r4806 = data; { - unsigned table = r4801 | r4802 << 8 | r4803 << 16; - unsigned index = r4804 << 2; - unsigned addr = table + index; - unsigned length = r4809 | r480a << 8; - unsigned mode = datarom_read(addr + 0); - unsigned offset = datarom_read(addr + 1) << 16 - | datarom_read(addr + 2) << 8 - | datarom_read(addr + 3) << 0; - - decomp.init(mode, offset, (r4805 | r4806 << 8) << mode); - r480c = 0x80; - } break; - + case 0x4806: r4806 = data; dcu_begin_transfer(); break; case 0x4807: r4807 = data; break; case 0x4808: break; case 0x4809: r4809 = data; break; @@ -279,7 +270,7 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) { case 0x4815: { if((addr & 1) == 0) r4814 = data, r4814_latch = true; if((addr & 1) == 1) r4815 = data, r4815_latch = true; - if(r4814_latch && r4815_latch) data_port_increment(); + if(r4814_latch && r4815_latch) data_port_increment_c(); } break; case 0x4816: r4816 = data; break; case 0x4817: r4817 = data; break; @@ -317,32 +308,33 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) { //==================== case 0x4840: r4840 = data & 0x03; { - if((r4840 & 1) == 0) rtc_reset(); + if(r4840 != 1) rtc_reset(); r4842 |= 0x80; - rtc_wait = rtc_delay; } break; case 0x4841: { - if((r4840 & 1) == 0) break; //RTC disabled? + if(r4840 != 1) break; //RTC disabled? + if(r4842 == 0) break; //RTC busy? r4842 |= 0x80; rtc_wait = rtc_delay; + rtc_mdr = data; if(rtc_mode == 0) { - r4841 = data & 0xf; rtc_mode = 1; rtc_addr = 0; + r4841 = rtc_mdr; break; } if(rtc_mode == 1) { - rtc_mode = r4841 == 0x0c ? 2 : r4841 == 0x3 ? 3 : 0; - rtc_addr = data & 0xf; + rtc_mode = 2; + rtc_addr = rtc_mdr; break; } - if(rtc_mode == 3) { - rtc_write(rtc_addr++, data); + if(r4841 == 0x03) { + rtc_write(rtc_addr++, rtc_mdr); break; } } diff --git a/bsnes/sfc/chip/spc7110/spc7110.hpp b/bsnes/sfc/chip/spc7110/spc7110.hpp index 278d0eb1..584ff432 100755 --- a/bsnes/sfc/chip/spc7110/spc7110.hpp +++ b/bsnes/sfc/chip/spc7110/spc7110.hpp @@ -6,7 +6,7 @@ struct SPC7110 : Coprocessor { enum : unsigned { mul_delay = 6, div_delay = 8, - rtc_delay = 24, + rtc_delay = 20, }; static void Enter(); @@ -32,6 +32,27 @@ struct SPC7110 : Coprocessor { void serialize(serializer&); 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); @@ -42,13 +63,11 @@ struct SPC7110 : Coprocessor { void set_data_offset(unsigned addr); void set_data_adjust(unsigned addr); - void data_port_read_a(); - void data_port_read_b(); void data_port_read(); void data_port_increment_a(); void data_port_increment_b(); - void data_port_increment(); + void data_port_increment_c(); //alu.cpp void alu_multiply(); @@ -82,15 +101,27 @@ private: uint8 r4804; //compression table index uint8 r4805; //decompression buffer index low uint8 r4806; //decompression buffer index high - uint8 r4807; //??? (used when $480b.d0 = 1) - uint8 r4808; //??? + uint8 r4807; //deinterleave length uint8 r4809; //compression length low uint8 r480a; //compression length high - uint8 r480b; //decompression control register + uint8 r480b; //deinterleave enable uint8 r480c; //decompression status - #include "decomp.hpp" - Decomp decomp; + 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]; //============== //data port unit @@ -146,13 +177,14 @@ private: //==================== uint8 r4840; //RTC enable uint8 r4841; //RTC data port - uint8 r4842; //RTC status + uint8 r4842; //RTC status (d7 = ready) uint22 rtc_clocks; unsigned rtc_seconds; - uint2 rtc_mode; //0 = idle, 1 = seek, 2 = read, 3 = write + unsigned rtc_mode; //0 = command, 1 = index, 2 = read or write uint4 rtc_addr; unsigned rtc_wait; + uint4 rtc_mdr; }; extern SPC7110 spc7110;