Update to v089r10 release.

byuu says:

Changelog:
- Cydrak merged all three SPC7110 decompression routines into one, cuts
  the size in half
- fixed masking of $4803.d7 and $4813.d7
- data port out of bounds accesses emulated correctly for app SPC7110
  boards
- all(?) data port $4810 reload cases now supported
- basic timing for $4805-6 seeking; reworked delay timing to work better
  as well
- fixed $480c.d7 flag (1 = ready, not busy)
- AbsoluteInput returns -32768 if presentation window lacks focus and
  you don't always allow input
This commit is contained in:
Tim Allen 2012-05-31 22:27:46 +10:00
parent 3302398907
commit 4545e7c62d
12 changed files with 299 additions and 514 deletions

View File

@ -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";
}

View File

@ -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);

View File

@ -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

View File

@ -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},
};
*/

View File

@ -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}},
};

View File

@ -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);

View File

@ -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
//============

View File

@ -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

View File

@ -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;

View File

@ -45,6 +45,7 @@ struct Application {
string titleFont;
string monospaceFont;
bool focused();
string path(const string &filename);
void commandLineLoad(string pathname);
void run();

View File

@ -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;

View File

@ -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();
}