Path: blob/master/libsnes/bsnes/snes/chip/spc7110/decomp.cpp
2 views
#ifdef SPC7110_CPP12uint8 SPC7110::Decomp::read() {3if(decomp_buffer_length == 0) {4//decompress at least (decomp_buffer_size / 2) bytes to the buffer5switch(decomp_mode) {6case 0: mode0(false); break;7case 1: mode1(false); break;8case 2: mode2(false); break;9default: return 0x00;10}11}1213uint8 data = decomp_buffer[decomp_buffer_rdoffset++];14decomp_buffer_rdoffset &= decomp_buffer_size - 1;15decomp_buffer_length--;16return data;17}1819void SPC7110::Decomp::write(uint8 data) {20decomp_buffer[decomp_buffer_wroffset++] = data;21decomp_buffer_wroffset &= decomp_buffer_size - 1;22decomp_buffer_length++;23}2425uint8 SPC7110::Decomp::dataread() {26unsigned size = cartridge.rom.size() - spc7110.data_rom_offset;27while(decomp_offset >= size) decomp_offset -= size;28return cartridge.rom.read(spc7110.data_rom_offset + decomp_offset++);29}3031void SPC7110::Decomp::init(unsigned mode, unsigned offset, unsigned index) {32decomp_mode = mode;33decomp_offset = offset;3435decomp_buffer_rdoffset = 0;36decomp_buffer_wroffset = 0;37decomp_buffer_length = 0;3839//reset context states40for(unsigned i = 0; i < 32; i++) {41context[i].index = 0;42context[i].invert = 0;43}4445switch(decomp_mode) {46case 0: mode0(true); break;47case 1: mode1(true); break;48case 2: mode2(true); break;49}5051//decompress up to requested output data index52while(index--) read();53}5455//5657void SPC7110::Decomp::mode0(bool init) {58static uint8 val, in, span;59static int out, inverts, lps, in_count;6061if(init == true) {62out = inverts = lps = 0;63span = 0xff;64val = dataread();65in = dataread();66in_count = 8;67return;68}6970while(decomp_buffer_length < (decomp_buffer_size >> 1)) {71for(unsigned bit = 0; bit < 8; bit++) {72//get context73uint8 mask = (1 << (bit & 3)) - 1;74uint8 con = mask + ((inverts & mask) ^ (lps & mask));75if(bit > 3) con += 15;7677//get prob and mps78unsigned prob = probability(con);79unsigned mps = (((out >> 15) & 1) ^ context[con].invert);8081//get bit82unsigned flag_lps;83if(val <= span - prob) { //mps84span = span - prob;85out = (out << 1) + mps;86flag_lps = 0;87} else { //lps88val = val - (span - (prob - 1));89span = prob - 1;90out = (out << 1) + 1 - mps;91flag_lps = 1;92}9394//renormalize95unsigned shift = 0;96while(span < 0x7f) {97shift++;9899span = (span << 1) + 1;100val = (val << 1) + (in >> 7);101102in <<= 1;103if(--in_count == 0) {104in = dataread();105in_count = 8;106}107}108109//update processing info110lps = (lps << 1) + flag_lps;111inverts = (inverts << 1) + context[con].invert;112113//update context state114if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;115if(flag_lps) context[con].index = next_lps(con);116else if(shift) context[con].index = next_mps(con);117}118119//save byte120write(out);121}122}123124void SPC7110::Decomp::mode1(bool init) {125static int pixelorder[4], realorder[4];126static uint8 in, val, span;127static int out, inverts, lps, in_count;128129if(init == true) {130for(unsigned i = 0; i < 4; i++) pixelorder[i] = i;131out = inverts = lps = 0;132span = 0xff;133val = dataread();134in = dataread();135in_count = 8;136return;137}138139while(decomp_buffer_length < (decomp_buffer_size >> 1)) {140for(unsigned pixel = 0; pixel < 8; pixel++) {141//get first symbol context142unsigned a = ((out >> (1 * 2)) & 3);143unsigned b = ((out >> (7 * 2)) & 3);144unsigned c = ((out >> (8 * 2)) & 3);145unsigned con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);146147//update pixel order148unsigned m, n;149for(m = 0; m < 4; m++) if(pixelorder[m] == a) break;150for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1];151pixelorder[0] = a;152153//calculate the real pixel order154for(m = 0; m < 4; m++) realorder[m] = pixelorder[m];155156//rotate reference pixel c value to top157for(m = 0; m < 4; m++) if(realorder[m] == c) break;158for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];159realorder[0] = c;160161//rotate reference pixel b value to top162for(m = 0; m < 4; m++) if(realorder[m] == b) break;163for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];164realorder[0] = b;165166//rotate reference pixel a value to top167for(m = 0; m < 4; m++) if(realorder[m] == a) break;168for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];169realorder[0] = a;170171//get 2 symbols172for(unsigned bit = 0; bit < 2; bit++) {173//get prob174unsigned prob = probability(con);175176//get symbol177unsigned flag_lps;178if(val <= span - prob) { //mps179span = span - prob;180flag_lps = 0;181} else { //lps182val = val - (span - (prob - 1));183span = prob - 1;184flag_lps = 1;185}186187//renormalize188unsigned shift = 0;189while(span < 0x7f) {190shift++;191192span = (span << 1) + 1;193val = (val << 1) + (in >> 7);194195in <<= 1;196if(--in_count == 0) {197in = dataread();198in_count = 8;199}200}201202//update processing info203lps = (lps << 1) + flag_lps;204inverts = (inverts << 1) + context[con].invert;205206//update context state207if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;208if(flag_lps) context[con].index = next_lps(con);209else if(shift) context[con].index = next_mps(con);210211//get next context212con = 5 + (con << 1) + ((lps ^ inverts) & 1);213}214215//get pixel216b = realorder[(lps ^ inverts) & 3];217out = (out << 2) + b;218}219220//turn pixel data into bitplanes221unsigned data = deinterleave_2x8(out);222write(data >> 8);223write(data >> 0);224}225}226227void SPC7110::Decomp::mode2(bool init) {228static int pixelorder[16], realorder[16];229static uint8 bitplanebuffer[16], buffer_index;230static uint8 in, val, span;231static int out0, out1, inverts, lps, in_count;232233if(init == true) {234for(unsigned i = 0; i < 16; i++) pixelorder[i] = i;235buffer_index = 0;236out0 = out1 = inverts = lps = 0;237span = 0xff;238val = dataread();239in = dataread();240in_count = 8;241return;242}243244while(decomp_buffer_length < (decomp_buffer_size >> 1)) {245for(unsigned pixel = 0; pixel < 8; pixel++) {246//get first symbol context247unsigned a = ((out0 >> (0 * 4)) & 15);248unsigned b = ((out0 >> (7 * 4)) & 15);249unsigned c = ((out1 >> (0 * 4)) & 15);250unsigned con = 0;251unsigned refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);252253//update pixel order254unsigned m, n;255for(m = 0; m < 16; m++) if(pixelorder[m] == a) break;256for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1];257pixelorder[0] = a;258259//calculate the real pixel order260for(m = 0; m < 16; m++) realorder[m] = pixelorder[m];261262//rotate reference pixel c value to top263for(m = 0; m < 16; m++) if(realorder[m] == c) break;264for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];265realorder[0] = c;266267//rotate reference pixel b value to top268for(m = 0; m < 16; m++) if(realorder[m] == b) break;269for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];270realorder[0] = b;271272//rotate reference pixel a value to top273for(m = 0; m < 16; m++) if(realorder[m] == a) break;274for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];275realorder[0] = a;276277//get 4 symbols278for(unsigned bit = 0; bit < 4; bit++) {279//get prob280unsigned prob = probability(con);281282//get symbol283unsigned flag_lps;284if(val <= span - prob) { //mps285span = span - prob;286flag_lps = 0;287} else { //lps288val = val - (span - (prob - 1));289span = prob - 1;290flag_lps = 1;291}292293//renormalize294unsigned shift = 0;295while(span < 0x7f) {296shift++;297298span = (span << 1) + 1;299val = (val << 1) + (in >> 7);300301in <<= 1;302if(--in_count == 0) {303in = dataread();304in_count = 8;305}306}307308//update processing info309lps = (lps << 1) + flag_lps;310unsigned invertbit = context[con].invert;311inverts = (inverts << 1) + invertbit;312313//update context state314if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;315if(flag_lps) context[con].index = next_lps(con);316else if(shift) context[con].index = next_mps(con);317318//get next context319con = mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0);320}321322//get pixel323b = realorder[(lps ^ inverts) & 0x0f];324out1 = (out1 << 4) + ((out0 >> 28) & 0x0f);325out0 = (out0 << 4) + b;326}327328//convert pixel data into bitplanes329unsigned data = deinterleave_4x8(out0);330write(data >> 24);331write(data >> 16);332bitplanebuffer[buffer_index++] = data >> 8;333bitplanebuffer[buffer_index++] = data >> 0;334335if(buffer_index == 16) {336for(unsigned i = 0; i < 16; i++) write(bitplanebuffer[i]);337buffer_index = 0;338}339}340}341342//343344const uint8 SPC7110::Decomp::evolution_table[53][4] = {345//{ prob, nextlps, nextmps, toggle invert },346347{ 0x5a, 1, 1, 1 },348{ 0x25, 6, 2, 0 },349{ 0x11, 8, 3, 0 },350{ 0x08, 10, 4, 0 },351{ 0x03, 12, 5, 0 },352{ 0x01, 15, 5, 0 },353354{ 0x5a, 7, 7, 1 },355{ 0x3f, 19, 8, 0 },356{ 0x2c, 21, 9, 0 },357{ 0x20, 22, 10, 0 },358{ 0x17, 23, 11, 0 },359{ 0x11, 25, 12, 0 },360{ 0x0c, 26, 13, 0 },361{ 0x09, 28, 14, 0 },362{ 0x07, 29, 15, 0 },363{ 0x05, 31, 16, 0 },364{ 0x04, 32, 17, 0 },365{ 0x03, 34, 18, 0 },366{ 0x02, 35, 5, 0 },367368{ 0x5a, 20, 20, 1 },369{ 0x48, 39, 21, 0 },370{ 0x3a, 40, 22, 0 },371{ 0x2e, 42, 23, 0 },372{ 0x26, 44, 24, 0 },373{ 0x1f, 45, 25, 0 },374{ 0x19, 46, 26, 0 },375{ 0x15, 25, 27, 0 },376{ 0x11, 26, 28, 0 },377{ 0x0e, 26, 29, 0 },378{ 0x0b, 27, 30, 0 },379{ 0x09, 28, 31, 0 },380{ 0x08, 29, 32, 0 },381{ 0x07, 30, 33, 0 },382{ 0x05, 31, 34, 0 },383{ 0x04, 33, 35, 0 },384{ 0x04, 33, 36, 0 },385{ 0x03, 34, 37, 0 },386{ 0x02, 35, 38, 0 },387{ 0x02, 36, 5, 0 },388389{ 0x58, 39, 40, 1 },390{ 0x4d, 47, 41, 0 },391{ 0x43, 48, 42, 0 },392{ 0x3b, 49, 43, 0 },393{ 0x34, 50, 44, 0 },394{ 0x2e, 51, 45, 0 },395{ 0x29, 44, 46, 0 },396{ 0x25, 45, 24, 0 },397398{ 0x56, 47, 48, 1 },399{ 0x4f, 47, 49, 0 },400{ 0x47, 48, 50, 0 },401{ 0x41, 49, 51, 0 },402{ 0x3c, 50, 52, 0 },403{ 0x37, 51, 43, 0 },404};405406const uint8 SPC7110::Decomp::mode2_context_table[32][2] = {407//{ next 0, next 1 },408409{ 1, 2 },410411{ 3, 8 },412{ 13, 14 },413414{ 15, 16 },415{ 17, 18 },416{ 19, 20 },417{ 21, 22 },418{ 23, 24 },419{ 25, 26 },420{ 25, 26 },421{ 25, 26 },422{ 25, 26 },423{ 25, 26 },424{ 27, 28 },425{ 29, 30 },426427{ 31, 31 },428{ 31, 31 },429{ 31, 31 },430{ 31, 31 },431{ 31, 31 },432{ 31, 31 },433{ 31, 31 },434{ 31, 31 },435{ 31, 31 },436{ 31, 31 },437{ 31, 31 },438{ 31, 31 },439{ 31, 31 },440{ 31, 31 },441{ 31, 31 },442{ 31, 31 },443444{ 31, 31 },445};446447uint8 SPC7110::Decomp::probability (unsigned n) { return evolution_table[context[n].index][0]; }448uint8 SPC7110::Decomp::next_lps (unsigned n) { return evolution_table[context[n].index][1]; }449uint8 SPC7110::Decomp::next_mps (unsigned n) { return evolution_table[context[n].index][2]; }450bool SPC7110::Decomp::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; }451452unsigned SPC7110::Decomp::deinterleave_2x8(unsigned data) {453//reverse morton lookup: de-interleave two 8-bit values454//15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8455//14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0456unsigned result = 0;457for(unsigned mask = 1u << 15; mask; mask >>= 2) result = (result << 1) | (bool)(data & mask);458for(unsigned mask = 1u << 14; mask; mask >>= 2) result = (result << 1) | (bool)(data & mask);459return result;460}461462unsigned SPC7110::Decomp::deinterleave_4x8(unsigned data) {463//reverse morton lookup: de-interleave four 8-bit values464//31, 27, 23, 19, 15, 11, 7, 3 -> 31-24465//30, 26, 22, 18, 14, 10, 6, 2 -> 23-16466//29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8467//28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0468unsigned result = 0;469for(unsigned mask = 1u << 31; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask);470for(unsigned mask = 1u << 30; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask);471for(unsigned mask = 1u << 29; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask);472for(unsigned mask = 1u << 28; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask);473return result;474}475476//477478void SPC7110::Decomp::reset() {479//mode 3 is invalid; this is treated as a special case to always return 0x00480//set to mode 3 so that reading decomp port before starting first decomp will return 0x00481decomp_mode = 3;482483decomp_buffer_rdoffset = 0;484decomp_buffer_wroffset = 0;485decomp_buffer_length = 0;486}487488SPC7110::Decomp::Decomp() {489decomp_buffer = new uint8_t[decomp_buffer_size];490reset();491}492493SPC7110::Decomp::~Decomp() {494delete[] decomp_buffer;495}496497#endif498499500