mirror of https://github.com/bsnes-emu/bsnes.git
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.)
This commit is contained in:
parent
6ac7b733bd
commit
0611fefefa
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue