mirror of https://github.com/bsnes-emu/bsnes.git
Update to v080r01 release.
byuu says: There was one unfortunate aspect of the S-DD1 module: you had to give it the DMA length and a target buffer, and it would do the entire decompression at once. Real hardware would work by streaming the data byte by byte. So with that, I went ahead and rewrote the code to handle byte-based streaming. This WIP is an important milestone for me personally. Up until now, bsnes has always had code that was directly copy-pasted from other authors. With all of the DSP and Cx4 chips rewritten in LLE, and the SPC7110 algorithm already ported over from C, and archive decompression code removed for a long time, the S-DD1 was the only module left like this. It's obviously not that big of a deal. The code is basically still a copy of the original. S-DD1 decomp from Andreas Naive, SPC7110 decomp from neviksti, and S-DSP from blargg. And the rest of the emulator is of course only possible because of code and research before it, although everything else has no resemblance at all to code before it. The main advantage, really, is absolute code consistency. I always use the same variant of K&R, for instance. I dunno, I guess I just never really liked the "Build-a-Bear Workshop" style of emulators, like is so prominent in the Genesis scene: "My new Genesis emu (uses Starscream/Musashi 68K core, Marat Fayzullin's Z80 core, YM2612 core from Game_Music_Emu, VDP core from Gens, SVP core from picodrive)", sorry, but you wrote a front-end, not an emulator :/ I also updated the SPC7110 decompression module: I merged the class inside the SPC7110 class (not sure why it was separate before), and replaced the morton lookup tables with for-loops. The morton tables were added to be a tiny bit faster when I was more interested in speed than code clarity. It may be a tiny bit slower (or faster due to less L2 cache usage), but you won't even notice an FPS drop, and it cuts out a good chunk of code and some tables. Lastly, I added pinput_poll() to video_refresh(). Forgot to remove Interface::input_poll() from the C++ side, will have to do that later.
This commit is contained in:
parent
5fc86eae6d
commit
8ae6444af7
|
@ -1,7 +1,7 @@
|
|||
include nall/Makefile
|
||||
snes := snes
|
||||
gameboy := gameboy
|
||||
profile := compatibility
|
||||
profile := accuracy
|
||||
ui := ui
|
||||
|
||||
# debugger
|
||||
|
|
|
@ -34,7 +34,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
|||
nvram.reset();
|
||||
|
||||
parse_xml(xml_list);
|
||||
print(xml_list[0], "\n\n");
|
||||
//print(xml_list[0], "\n\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
//S-DD1 decompression algorithm implementation
|
||||
//original code written by Andreas Naive (public domain license)
|
||||
//bsnes port written by byuu
|
||||
|
||||
//note: decompression module does not need to be serialized with bsnes
|
||||
//this is because decompression only runs during DMA, and bsnes will complete
|
||||
//any pending DMA transfers prior to serialization.
|
||||
|
||||
//input manager
|
||||
|
||||
void SDD1::Decomp::IM::init(unsigned offset_) {
|
||||
offset = offset_;
|
||||
bit_count = 4;
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::IM::get_codeword(uint8 code_length) {
|
||||
uint8 codeword;
|
||||
uint8 comp_count;
|
||||
|
||||
codeword = self.rom_read(offset) << bit_count;
|
||||
bit_count++;
|
||||
|
||||
if(codeword & 0x80) {
|
||||
codeword |= self.rom_read(offset + 1) >> (9 - bit_count);
|
||||
bit_count += code_length;
|
||||
}
|
||||
|
||||
if(bit_count & 0x08) {
|
||||
offset++;
|
||||
bit_count &= 0x07;
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
//golomb-code decoder
|
||||
|
||||
const uint8 SDD1::Decomp::GCD::run_count[] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
|
||||
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
|
||||
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
|
||||
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
|
||||
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
|
||||
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
|
||||
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
|
||||
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
|
||||
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
|
||||
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
|
||||
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
|
||||
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
|
||||
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
|
||||
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
|
||||
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
|
||||
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
|
||||
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
|
||||
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
|
||||
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
|
||||
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
|
||||
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
|
||||
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
|
||||
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
|
||||
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
|
||||
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
|
||||
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
|
||||
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
|
||||
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
|
||||
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
|
||||
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
|
||||
};
|
||||
|
||||
void SDD1::Decomp::GCD::get_run_count(uint8 code_number, uint8 &mps_count, bool &lps_index) {
|
||||
uint8 codeword = self.im.get_codeword(code_number);
|
||||
|
||||
if(codeword & 0x80) {
|
||||
lps_index = 1;
|
||||
mps_count = run_count[codeword >> (code_number ^ 0x07)];
|
||||
} else {
|
||||
mps_count = 1 << code_number;
|
||||
}
|
||||
}
|
||||
|
||||
//bits generator
|
||||
|
||||
void SDD1::Decomp::BG::init() {
|
||||
mps_count = 0;
|
||||
lps_index = 0;
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::BG::get_bit(bool &end_of_run) {
|
||||
if(!(mps_count || lps_index)) self.gcd.get_run_count(code_number, mps_count, lps_index);
|
||||
|
||||
uint8 bit;
|
||||
if(mps_count) {
|
||||
bit = 0;
|
||||
mps_count--;
|
||||
} else {
|
||||
bit = 1;
|
||||
lps_index = 0;
|
||||
}
|
||||
|
||||
end_of_run = !(mps_count || lps_index);
|
||||
return bit;
|
||||
}
|
||||
|
||||
//probability estimation module
|
||||
|
||||
const SDD1::Decomp::PEM::State SDD1::Decomp::PEM::evolution_table[33] = {
|
||||
{ 0, 25, 25 },
|
||||
{ 0, 2, 1 },
|
||||
{ 0, 3, 1 },
|
||||
{ 0, 4, 2 },
|
||||
{ 0, 5, 3 },
|
||||
{ 1, 6, 4 },
|
||||
{ 1, 7, 5 },
|
||||
{ 1, 8, 6 },
|
||||
{ 1, 9, 7 },
|
||||
{ 2, 10, 8 },
|
||||
{ 2, 11, 9 },
|
||||
{ 2, 12, 10 },
|
||||
{ 2, 13, 11 },
|
||||
{ 3, 14, 12 },
|
||||
{ 3, 15, 13 },
|
||||
{ 3, 16, 14 },
|
||||
{ 3, 17, 15 },
|
||||
{ 4, 18, 16 },
|
||||
{ 4, 19, 17 },
|
||||
{ 5, 20, 18 },
|
||||
{ 5, 21, 19 },
|
||||
{ 6, 22, 20 },
|
||||
{ 6, 23, 21 },
|
||||
{ 7, 24, 22 },
|
||||
{ 7, 24, 23 },
|
||||
{ 0, 26, 1 },
|
||||
{ 1, 27, 2 },
|
||||
{ 2, 28, 4 },
|
||||
{ 3, 29, 8 },
|
||||
{ 4, 30, 12 },
|
||||
{ 5, 31, 16 },
|
||||
{ 6, 32, 18 },
|
||||
{ 7, 24, 22 },
|
||||
};
|
||||
|
||||
void SDD1::Decomp::PEM::init() {
|
||||
for(unsigned i = 0; i < 32; i++) {
|
||||
context_info[i].status = 0;
|
||||
context_info[i].mps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::PEM::get_bit(uint8 context) {
|
||||
ContextInfo &info = context_info[context];
|
||||
uint8 current_status = info.status;
|
||||
uint8 current_mps = info.mps;
|
||||
const State &s = SDD1::Decomp::PEM::evolution_table[current_status];
|
||||
|
||||
uint8 bit;
|
||||
bool end_of_run;
|
||||
switch(s.code_number) {
|
||||
case 0: bit = self.bg0.get_bit(end_of_run); break;
|
||||
case 1: bit = self.bg1.get_bit(end_of_run); break;
|
||||
case 2: bit = self.bg2.get_bit(end_of_run); break;
|
||||
case 3: bit = self.bg3.get_bit(end_of_run); break;
|
||||
case 4: bit = self.bg4.get_bit(end_of_run); break;
|
||||
case 5: bit = self.bg5.get_bit(end_of_run); break;
|
||||
case 6: bit = self.bg6.get_bit(end_of_run); break;
|
||||
case 7: bit = self.bg7.get_bit(end_of_run); break;
|
||||
}
|
||||
|
||||
if(end_of_run) {
|
||||
if(bit) {
|
||||
if(!(current_status & 0xfe)) info.mps ^= 0x01;
|
||||
info.status = s.next_if_lps;
|
||||
} else {
|
||||
info.status = s.next_if_mps;
|
||||
}
|
||||
}
|
||||
|
||||
return bit ^ current_mps;
|
||||
}
|
||||
|
||||
//context model
|
||||
|
||||
void SDD1::Decomp::CM::init(unsigned offset) {
|
||||
bitplanes_info = self.rom_read(offset) & 0xc0;
|
||||
context_bits_info = self.rom_read(offset) & 0x30;
|
||||
bit_number = 0;
|
||||
for(unsigned i = 0; i < 8; i++) previous_bitplane_bits[i] = 0;
|
||||
switch(bitplanes_info) {
|
||||
case 0x00: current_bitplane = 1; break;
|
||||
case 0x40: current_bitplane = 7; break;
|
||||
case 0x80: current_bitplane = 3; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::CM::get_bit() {
|
||||
switch(bitplanes_info) {
|
||||
case 0x00:
|
||||
current_bitplane ^= 0x01;
|
||||
break;
|
||||
case 0x40:
|
||||
current_bitplane ^= 0x01;
|
||||
if(!(bit_number & 0x7f)) current_bitplane = ((current_bitplane + 2) & 0x07);
|
||||
break;
|
||||
case 0x80:
|
||||
current_bitplane ^= 0x01;
|
||||
if(!(bit_number & 0x7f)) current_bitplane ^= 0x02;
|
||||
break;
|
||||
case 0xc0:
|
||||
current_bitplane = bit_number & 0x07;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16 &context_bits = previous_bitplane_bits[current_bitplane];
|
||||
uint8 current_context = (current_bitplane & 0x01) << 4;
|
||||
switch(context_bits_info) {
|
||||
case 0x00: current_context |= ((context_bits & 0x01c0) >> 5) | (context_bits & 0x0001); break;
|
||||
case 0x10: current_context |= ((context_bits & 0x0180) >> 5) | (context_bits & 0x0001); break;
|
||||
case 0x20: current_context |= ((context_bits & 0x00c0) >> 5) | (context_bits & 0x0001); break;
|
||||
case 0x30: current_context |= ((context_bits & 0x0180) >> 5) | (context_bits & 0x0003); break;
|
||||
}
|
||||
|
||||
uint8 bit = self.pem.get_bit(current_context);
|
||||
context_bits <<= 1;
|
||||
context_bits |= bit;
|
||||
bit_number++;
|
||||
return bit;
|
||||
}
|
||||
|
||||
//output logic
|
||||
|
||||
void SDD1::Decomp::OL::init(unsigned offset) {
|
||||
bitplanes_info = self.rom_read(offset) & 0xc0;
|
||||
r0 = 0x01;
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::OL::decompress() {
|
||||
switch(bitplanes_info) {
|
||||
case 0x00: case 0x40: case 0x80:
|
||||
if(r0 == 0) {
|
||||
r0 = ~r0;
|
||||
return r2;
|
||||
}
|
||||
for(r0 = 0x80, r1 = 0, r2 = 0; r0; r0 >>= 1) {
|
||||
if(self.cm.get_bit()) r1 |= r0;
|
||||
if(self.cm.get_bit()) r2 |= r0;
|
||||
}
|
||||
return r1;
|
||||
case 0xc0:
|
||||
for(r0 = 0x01, r1 = 0; r0; r0 <<= 1) {
|
||||
if(self.cm.get_bit()) r1 |= r0;
|
||||
}
|
||||
return r1;
|
||||
}
|
||||
}
|
||||
|
||||
//core
|
||||
|
||||
void SDD1::Decomp::init(unsigned offset) {
|
||||
im.init(offset);
|
||||
bg0.init();
|
||||
bg1.init();
|
||||
bg2.init();
|
||||
bg3.init();
|
||||
bg4.init();
|
||||
bg5.init();
|
||||
bg6.init();
|
||||
bg7.init();
|
||||
pem.init();
|
||||
cm.init(offset);
|
||||
ol.init(offset);
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::read() {
|
||||
return ol.decompress();
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::rom_read(unsigned offset) {
|
||||
return sdd1.rom_read(offset);
|
||||
}
|
||||
|
||||
SDD1::Decomp::Decomp() : im(*this), gcd(*this),
|
||||
bg0(*this, 0), bg1(*this, 1), bg2(*this, 2), bg3(*this, 3),
|
||||
bg4(*this, 4), bg5(*this, 5), bg6(*this, 6), bg7(*this, 7),
|
||||
pem(*this), cm(*this), ol(*this) {
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
struct Decomp {
|
||||
struct IM { //input manager
|
||||
Decomp &self;
|
||||
void init(unsigned offset);
|
||||
uint8 get_codeword(uint8 code_length);
|
||||
IM(SDD1::Decomp &self) : self(self) {}
|
||||
private:
|
||||
unsigned offset;
|
||||
unsigned bit_count;
|
||||
};
|
||||
|
||||
struct GCD { //golomb-code decoder
|
||||
Decomp &self;
|
||||
static const uint8 run_count[256];
|
||||
void get_run_count(uint8 code_number, uint8 &mps_count, bool &lps_index);
|
||||
GCD(SDD1::Decomp &self) : self(self) {}
|
||||
};
|
||||
|
||||
struct BG { //bits generator
|
||||
Decomp &self;
|
||||
void init();
|
||||
uint8 get_bit(bool &end_of_run);
|
||||
BG(SDD1::Decomp &self, uint8 code_number) : self(self), code_number(code_number) {}
|
||||
private:
|
||||
const uint8 code_number;
|
||||
uint8 mps_count;
|
||||
bool lps_index;
|
||||
};
|
||||
|
||||
struct PEM { //probability estimation module
|
||||
Decomp &self;
|
||||
void init();
|
||||
uint8 get_bit(uint8 context);
|
||||
PEM(SDD1::Decomp &self) : self(self) {}
|
||||
private:
|
||||
struct State {
|
||||
uint8 code_number;
|
||||
uint8 next_if_mps;
|
||||
uint8 next_if_lps;
|
||||
};
|
||||
static const State evolution_table[33];
|
||||
struct ContextInfo {
|
||||
uint8 status;
|
||||
uint8 mps;
|
||||
} context_info[32];
|
||||
};
|
||||
|
||||
struct CM { //context model
|
||||
Decomp &self;
|
||||
void init(unsigned offset);
|
||||
uint8 get_bit();
|
||||
CM(SDD1::Decomp &self) : self(self) {}
|
||||
private:
|
||||
uint8 bitplanes_info;
|
||||
uint8 context_bits_info;
|
||||
uint8 bit_number;
|
||||
uint8 current_bitplane;
|
||||
uint16 previous_bitplane_bits[8];
|
||||
};
|
||||
|
||||
struct OL { //output logic
|
||||
Decomp &self;
|
||||
void init(unsigned offset);
|
||||
uint8 decompress();
|
||||
OL(SDD1::Decomp &self) : self(self) {}
|
||||
private:
|
||||
uint8 bitplanes_info;
|
||||
uint8 r0, r1, r2;
|
||||
};
|
||||
|
||||
void init(unsigned offset);
|
||||
uint8 read();
|
||||
uint8 rom_read(unsigned offset);
|
||||
Decomp();
|
||||
|
||||
IM im;
|
||||
GCD gcd;
|
||||
BG bg0, bg1, bg2, bg3, bg4, bg5, bg6, bg7;
|
||||
PEM pem;
|
||||
CM cm;
|
||||
OL ol;
|
||||
};
|
|
@ -5,8 +5,8 @@ namespace SNES {
|
|||
|
||||
SDD1 sdd1;
|
||||
|
||||
#include "decomp.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ void SDD1::power() {
|
|||
void SDD1::reset() {
|
||||
sdd1_enable = 0x00;
|
||||
xfer_enable = 0x00;
|
||||
dma_ready = false;
|
||||
|
||||
mmc[0] = 0 << 20;
|
||||
mmc[1] = 1 << 20;
|
||||
|
@ -38,8 +39,6 @@ void SDD1::reset() {
|
|||
dma[i].addr = 0;
|
||||
dma[i].size = 0;
|
||||
}
|
||||
|
||||
buffer.ready = false;
|
||||
}
|
||||
|
||||
uint8 SDD1::mmio_read(unsigned addr) {
|
||||
|
@ -86,6 +85,10 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8 SDD1::rom_read(unsigned addr) {
|
||||
return cartridge.rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff
|
||||
//the design is meant to be as close to the hardware design as possible, thus this code
|
||||
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
|
||||
|
@ -111,26 +114,16 @@ uint8 SDD1::mcu_read(unsigned addr) {
|
|||
if(sdd1_enable & xfer_enable & (1 << i)) {
|
||||
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
|
||||
if(addr == dma[i].addr) {
|
||||
if(!buffer.ready) {
|
||||
//first byte read for channel performs full decompression.
|
||||
//this really should stream byte-by-byte, but it's not necessary since the size is known
|
||||
buffer.offset = 0;
|
||||
buffer.size = dma[i].size ? dma[i].size : 65536;
|
||||
|
||||
//sdd1emu calls this function; it needs to access uncompressed data;
|
||||
//so temporarily disable decompression mode for decompress() call.
|
||||
uint8 temp = sdd1_enable;
|
||||
sdd1_enable = false;
|
||||
sdd1emu.decompress(addr, buffer.size, buffer.data);
|
||||
sdd1_enable = temp;
|
||||
|
||||
buffer.ready = true;
|
||||
if(!dma_ready) {
|
||||
//prepare streaming decompression
|
||||
decomp.init(addr);
|
||||
dma_ready = true;
|
||||
}
|
||||
|
||||
//fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
|
||||
uint8 data = buffer.data[(uint16)buffer.offset++];
|
||||
if(buffer.offset >= buffer.size) {
|
||||
buffer.ready = false;
|
||||
//fetch a decompressed byte; once finished, disable channel and invalidate buffer
|
||||
uint8 data = decomp.read();
|
||||
if(--dma[i].size == 0) {
|
||||
dma_ready = false;
|
||||
xfer_enable &= ~(1 << i);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include "sdd1emu.hpp"
|
||||
|
||||
class SDD1 {
|
||||
public:
|
||||
void init();
|
||||
|
@ -11,6 +9,7 @@ public:
|
|||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 rom_read(unsigned addr);
|
||||
uint8 mcu_read(unsigned addr);
|
||||
void mcu_write(unsigned addr, uint8 data);
|
||||
|
||||
|
@ -19,22 +18,19 @@ public:
|
|||
~SDD1();
|
||||
|
||||
private:
|
||||
uint8 sdd1_enable; //channel bit-mask
|
||||
uint8 xfer_enable; //channel bit-mask
|
||||
unsigned mmc[4]; //memory map controller ROM indices
|
||||
uint8 sdd1_enable; //channel bit-mask
|
||||
uint8 xfer_enable; //channel bit-mask
|
||||
bool dma_ready; //used to initialize decompression module
|
||||
unsigned mmc[4]; //memory map controller ROM indices
|
||||
|
||||
struct {
|
||||
unsigned addr; //$43x2-$43x4 -- DMA transfer address
|
||||
uint16 size; //$43x5-$43x6 -- DMA transfer size
|
||||
unsigned addr; //$43x2-$43x4 -- DMA transfer address
|
||||
uint16 size; //$43x5-$43x6 -- DMA transfer size
|
||||
} dma[8];
|
||||
|
||||
SDD1emu sdd1emu;
|
||||
struct {
|
||||
uint8 data[65536]; //pointer to decompressed S-DD1 data
|
||||
uint16 offset; //read index into S-DD1 decompression buffer
|
||||
unsigned size; //length of data buffer; reads decrement counter, set ready to false at 0
|
||||
bool ready; //true when data[] is valid; false to invoke sdd1emu.decompress()
|
||||
} buffer;
|
||||
public:
|
||||
#include "decomp.hpp"
|
||||
Decomp decomp;
|
||||
};
|
||||
|
||||
extern SDD1 sdd1;
|
||||
|
|
|
@ -1,452 +0,0 @@
|
|||
#ifdef SDD1_CPP
|
||||
|
||||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
typedef uint8 bool8;
|
||||
#define SDD1_read(__addr) (sdd1.mcu_read(__addr))
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_IM::prepareDecomp(uint32 in_buf) {
|
||||
|
||||
byte_ptr=in_buf;
|
||||
bit_count=4;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_IM::getCodeword(uint8 code_len) {
|
||||
|
||||
uint8 codeword;
|
||||
uint8 comp_count;
|
||||
|
||||
codeword = (SDD1_read(byte_ptr))<<bit_count;
|
||||
|
||||
++bit_count;
|
||||
|
||||
if (codeword & 0x80) {
|
||||
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
|
||||
bit_count+=code_len;
|
||||
}
|
||||
|
||||
if (bit_count & 0x08) {
|
||||
byte_ptr++;
|
||||
bit_count&=0x07;
|
||||
}
|
||||
|
||||
return codeword;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
|
||||
IM(associatedIM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
|
||||
|
||||
const uint8 run_count[] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
|
||||
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
|
||||
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
|
||||
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
|
||||
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
|
||||
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
|
||||
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
|
||||
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
|
||||
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
|
||||
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
|
||||
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
|
||||
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
|
||||
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
|
||||
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
|
||||
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
|
||||
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
|
||||
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
|
||||
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
|
||||
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
|
||||
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
|
||||
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
|
||||
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
|
||||
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
|
||||
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
|
||||
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
|
||||
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
|
||||
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
|
||||
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
|
||||
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
|
||||
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
|
||||
};
|
||||
|
||||
uint8 codeword=IM->getCodeword(code_num);
|
||||
|
||||
if (codeword & 0x80) {
|
||||
*LPSind=1;
|
||||
*MPScount=run_count[codeword>>(code_num^0x07)];
|
||||
}
|
||||
else {
|
||||
*MPScount=(1<<code_num);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
|
||||
GCD(associatedGCD), code_num(code)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_BG::prepareDecomp(void) {
|
||||
|
||||
MPScount=0;
|
||||
LPSind=0;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
|
||||
|
||||
uint8 bit;
|
||||
|
||||
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
|
||||
|
||||
if (MPScount) {
|
||||
bit=0;
|
||||
MPScount--;
|
||||
}
|
||||
else {
|
||||
bit=1;
|
||||
LPSind=0;
|
||||
}
|
||||
|
||||
if (MPScount || LPSind) (*endOfRun)=0;
|
||||
else (*endOfRun)=1;
|
||||
|
||||
return bit;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
|
||||
|
||||
BG[0]=associatedBG0;
|
||||
BG[1]=associatedBG1;
|
||||
BG[2]=associatedBG2;
|
||||
BG[3]=associatedBG3;
|
||||
BG[4]=associatedBG4;
|
||||
BG[5]=associatedBG5;
|
||||
BG[6]=associatedBG6;
|
||||
BG[7]=associatedBG7;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
|
||||
{ 0,25,25},
|
||||
{ 0, 2, 1},
|
||||
{ 0, 3, 1},
|
||||
{ 0, 4, 2},
|
||||
{ 0, 5, 3},
|
||||
{ 1, 6, 4},
|
||||
{ 1, 7, 5},
|
||||
{ 1, 8, 6},
|
||||
{ 1, 9, 7},
|
||||
{ 2,10, 8},
|
||||
{ 2,11, 9},
|
||||
{ 2,12,10},
|
||||
{ 2,13,11},
|
||||
{ 3,14,12},
|
||||
{ 3,15,13},
|
||||
{ 3,16,14},
|
||||
{ 3,17,15},
|
||||
{ 4,18,16},
|
||||
{ 4,19,17},
|
||||
{ 5,20,18},
|
||||
{ 5,21,19},
|
||||
{ 6,22,20},
|
||||
{ 6,23,21},
|
||||
{ 7,24,22},
|
||||
{ 7,24,23},
|
||||
{ 0,26, 1},
|
||||
{ 1,27, 2},
|
||||
{ 2,28, 4},
|
||||
{ 3,29, 8},
|
||||
{ 4,30,12},
|
||||
{ 5,31,16},
|
||||
{ 6,32,18},
|
||||
{ 7,24,22}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_PEM::prepareDecomp(void) {
|
||||
|
||||
for (uint8 i=0; i<32; i++) {
|
||||
contextInfo[i].status=0;
|
||||
contextInfo[i].MPS=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_PEM::getBit(uint8 context) {
|
||||
|
||||
bool8 endOfRun;
|
||||
uint8 bit;
|
||||
|
||||
SDD1_ContextInfo *pContInfo=&contextInfo[context];
|
||||
uint8 currStatus = pContInfo->status;
|
||||
const state *pState=&SDD1_PEM::evolution_table[currStatus];
|
||||
uint8 currentMPS=pContInfo->MPS;
|
||||
|
||||
bit=(BG[pState->code_num])->getBit(&endOfRun);
|
||||
|
||||
if (endOfRun)
|
||||
if (bit) {
|
||||
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
|
||||
(pContInfo->status)=pState->nextIfLPS;
|
||||
}
|
||||
else
|
||||
(pContInfo->status)=pState->nextIfMPS;
|
||||
|
||||
return bit^currentMPS;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
|
||||
PEM(associatedPEM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_CM::prepareDecomp(uint32 first_byte) {
|
||||
|
||||
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||
contextBitsInfo = SDD1_read(first_byte) & 0x30;
|
||||
bit_number=0;
|
||||
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
currBitplane = 1;
|
||||
break;
|
||||
case 0x40:
|
||||
currBitplane = 7;
|
||||
break;
|
||||
case 0x80:
|
||||
currBitplane = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_CM::getBit(void) {
|
||||
|
||||
uint8 currContext;
|
||||
uint16 *context_bits;
|
||||
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
currBitplane ^= 0x01;
|
||||
break;
|
||||
case 0x40:
|
||||
currBitplane ^= 0x01;
|
||||
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
|
||||
break;
|
||||
case 0x80:
|
||||
currBitplane ^= 0x01;
|
||||
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
|
||||
break;
|
||||
case 0xc0:
|
||||
currBitplane = bit_number & 0x07;
|
||||
}
|
||||
|
||||
context_bits = &prevBitplaneBits[currBitplane];
|
||||
|
||||
currContext=(currBitplane & 0x01)<<4;
|
||||
switch (contextBitsInfo) {
|
||||
case 0x00:
|
||||
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x10:
|
||||
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x20:
|
||||
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x30:
|
||||
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
|
||||
}
|
||||
|
||||
uint8 bit=PEM->getBit(currContext);
|
||||
|
||||
*context_bits <<= 1;
|
||||
*context_bits |= bit;
|
||||
|
||||
bit_number++;
|
||||
|
||||
return bit;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
|
||||
CM(associatedCM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
|
||||
|
||||
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||
length=out_len;
|
||||
buffer=out_buf;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_OL::launch(void) {
|
||||
|
||||
uint8 i;
|
||||
uint8 register1, register2;
|
||||
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
case 0x40:
|
||||
case 0x80:
|
||||
i=1;
|
||||
do { //if length==0, we output 2^16 bytes
|
||||
if (!i) {
|
||||
*(buffer++)=register2;
|
||||
i=~i;
|
||||
}
|
||||
else {
|
||||
for (register1=register2=0, i=0x80; i; i>>=1) {
|
||||
if (CM->getBit()) register1 |= i;
|
||||
if (CM->getBit()) register2 |= i;
|
||||
}
|
||||
*(buffer++)=register1;
|
||||
}
|
||||
} while (--length);
|
||||
break;
|
||||
case 0xc0:
|
||||
do {
|
||||
for (register1=0, i=0x01; i; i<<=1) {
|
||||
if (CM->getBit()) register1 |= i;
|
||||
}
|
||||
*(buffer++)=register1;
|
||||
} while (--length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
|
||||
|
||||
IM.prepareDecomp(in_buf);
|
||||
BG0.prepareDecomp();
|
||||
BG1.prepareDecomp();
|
||||
BG2.prepareDecomp();
|
||||
BG3.prepareDecomp();
|
||||
BG4.prepareDecomp();
|
||||
BG5.prepareDecomp();
|
||||
BG6.prepareDecomp();
|
||||
BG7.prepareDecomp();
|
||||
PEM.prepareDecomp();
|
||||
CM.prepareDecomp(in_buf);
|
||||
OL.prepareDecomp(in_buf, out_len, out_buf);
|
||||
|
||||
OL.launch();
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1emu::SDD1emu() :
|
||||
GCD(&IM),
|
||||
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
|
||||
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
|
||||
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
|
||||
CM(&PEM),
|
||||
OL(&CM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
#endif
|
|
@ -1,164 +0,0 @@
|
|||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#define bool8 uint8
|
||||
|
||||
class SDD1_IM { //Input Manager
|
||||
|
||||
public:
|
||||
SDD1_IM(void) {}
|
||||
void prepareDecomp(uint32 in_buf);
|
||||
uint8 getCodeword(const uint8 code_len);
|
||||
|
||||
private:
|
||||
uint32 byte_ptr;
|
||||
uint8 bit_count;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_GCD { //Golomb-Code Decoder
|
||||
|
||||
public:
|
||||
SDD1_GCD(SDD1_IM *associatedIM);
|
||||
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
|
||||
|
||||
private:
|
||||
SDD1_IM *const IM;
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_BG { // Bits Generator
|
||||
|
||||
public:
|
||||
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(bool8 *endOfRun);
|
||||
|
||||
private:
|
||||
const uint8 code_num;
|
||||
uint8 MPScount;
|
||||
bool8 LPSind;
|
||||
SDD1_GCD *const GCD;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_PEM { //Probability Estimation Module
|
||||
|
||||
public:
|
||||
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(uint8 context);
|
||||
|
||||
private:
|
||||
struct state {
|
||||
uint8 code_num;
|
||||
uint8 nextIfMPS;
|
||||
uint8 nextIfLPS;
|
||||
};
|
||||
static const state evolution_table[];
|
||||
struct SDD1_ContextInfo {
|
||||
uint8 status;
|
||||
uint8 MPS;
|
||||
} contextInfo[32];
|
||||
SDD1_BG * BG[8];
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_CM { //Context Model
|
||||
|
||||
public:
|
||||
SDD1_CM(SDD1_PEM *associatedPEM);
|
||||
void prepareDecomp(uint32 first_byte);
|
||||
uint8 getBit(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint8 contextBitsInfo;
|
||||
uint8 bit_number;
|
||||
uint8 currBitplane;
|
||||
uint16 prevBitplaneBits[8];
|
||||
SDD1_PEM *const PEM;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_OL { //Output Logic
|
||||
|
||||
public:
|
||||
SDD1_OL(SDD1_CM *associatedCM);
|
||||
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
|
||||
void launch(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint16 length;
|
||||
uint8 *buffer;
|
||||
SDD1_CM *const CM;
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1emu {
|
||||
|
||||
public:
|
||||
SDD1emu(void);
|
||||
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
|
||||
|
||||
private:
|
||||
SDD1_IM IM;
|
||||
SDD1_GCD GCD;
|
||||
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
|
||||
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
|
||||
SDD1_PEM PEM;
|
||||
SDD1_CM CM;
|
||||
SDD1_OL OL;
|
||||
|
||||
};
|
||||
|
||||
#undef bool8
|
|
@ -3,17 +3,13 @@
|
|||
void SDD1::serialize(serializer &s) {
|
||||
s.integer(sdd1_enable);
|
||||
s.integer(xfer_enable);
|
||||
s.integer(dma_ready);
|
||||
s.array(mmc);
|
||||
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
s.integer(dma[n].addr);
|
||||
s.integer(dma[n].size);
|
||||
}
|
||||
|
||||
s.array(buffer.data);
|
||||
s.integer(buffer.offset);
|
||||
s.integer(buffer.size);
|
||||
s.integer(buffer.ready);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SPC7110_CPP
|
||||
|
||||
uint8 SPC7110Decomp::read() {
|
||||
uint8 SPC7110::Decomp::read() {
|
||||
if(decomp_buffer_length == 0) {
|
||||
//decompress at least (decomp_buffer_size / 2) bytes to the buffer
|
||||
switch(decomp_mode) {
|
||||
|
@ -17,19 +17,19 @@ uint8 SPC7110Decomp::read() {
|
|||
return data;
|
||||
}
|
||||
|
||||
void SPC7110Decomp::write(uint8 data) {
|
||||
void SPC7110::Decomp::write(uint8 data) {
|
||||
decomp_buffer[decomp_buffer_wroffset++] = data;
|
||||
decomp_buffer_wroffset &= decomp_buffer_size - 1;
|
||||
decomp_buffer_length++;
|
||||
}
|
||||
|
||||
uint8 SPC7110Decomp::dataread() {
|
||||
uint8 SPC7110::Decomp::dataread() {
|
||||
unsigned size = cartridge.rom.size() - spc7110.data_rom_offset;
|
||||
while(decomp_offset >= size) decomp_offset -= size;
|
||||
return cartridge.rom.read(spc7110.data_rom_offset + decomp_offset++);
|
||||
}
|
||||
|
||||
void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {
|
||||
void SPC7110::Decomp::init(unsigned mode, unsigned offset, unsigned index) {
|
||||
decomp_mode = mode;
|
||||
decomp_offset = offset;
|
||||
|
||||
|
@ -55,7 +55,7 @@ void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {
|
|||
|
||||
//
|
||||
|
||||
void SPC7110Decomp::mode0(bool init) {
|
||||
void SPC7110::Decomp::mode0(bool init) {
|
||||
static uint8 val, in, span;
|
||||
static int out, inverts, lps, in_count;
|
||||
|
||||
|
@ -122,7 +122,7 @@ void SPC7110Decomp::mode0(bool init) {
|
|||
}
|
||||
}
|
||||
|
||||
void SPC7110Decomp::mode1(bool init) {
|
||||
void SPC7110::Decomp::mode1(bool init) {
|
||||
static int pixelorder[4], realorder[4];
|
||||
static uint8 in, val, span;
|
||||
static int out, inverts, lps, in_count;
|
||||
|
@ -219,13 +219,13 @@ void SPC7110Decomp::mode1(bool init) {
|
|||
}
|
||||
|
||||
//turn pixel data into bitplanes
|
||||
unsigned data = morton_2x8(out);
|
||||
unsigned data = deinterleave_2x8(out);
|
||||
write(data >> 8);
|
||||
write(data >> 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SPC7110Decomp::mode2(bool init) {
|
||||
void SPC7110::Decomp::mode2(bool init) {
|
||||
static int pixelorder[16], realorder[16];
|
||||
static uint8 bitplanebuffer[16], buffer_index;
|
||||
static uint8 in, val, span;
|
||||
|
@ -327,7 +327,7 @@ void SPC7110Decomp::mode2(bool init) {
|
|||
}
|
||||
|
||||
//convert pixel data into bitplanes
|
||||
unsigned data = morton_4x8(out0);
|
||||
unsigned data = deinterleave_4x8(out0);
|
||||
write(data >> 24);
|
||||
write(data >> 16);
|
||||
bitplanebuffer[buffer_index++] = data >> 8;
|
||||
|
@ -342,7 +342,7 @@ void SPC7110Decomp::mode2(bool init) {
|
|||
|
||||
//
|
||||
|
||||
const uint8 SPC7110Decomp::evolution_table[53][4] = {
|
||||
const uint8 SPC7110::Decomp::evolution_table[53][4] = {
|
||||
//{ prob, nextlps, nextmps, toggle invert },
|
||||
|
||||
{ 0x5a, 1, 1, 1 },
|
||||
|
@ -404,7 +404,7 @@ const uint8 SPC7110Decomp::evolution_table[53][4] = {
|
|||
{ 0x37, 51, 43, 0 },
|
||||
};
|
||||
|
||||
const uint8 SPC7110Decomp::mode2_context_table[32][2] = {
|
||||
const uint8 SPC7110::Decomp::mode2_context_table[32][2] = {
|
||||
//{ next 0, next 1 },
|
||||
|
||||
{ 1, 2 },
|
||||
|
@ -445,31 +445,38 @@ const uint8 SPC7110Decomp::mode2_context_table[32][2] = {
|
|||
{ 31, 31 },
|
||||
};
|
||||
|
||||
uint8 SPC7110Decomp::probability (unsigned n) { return evolution_table[context[n].index][0]; }
|
||||
uint8 SPC7110Decomp::next_lps (unsigned n) { return evolution_table[context[n].index][1]; }
|
||||
uint8 SPC7110Decomp::next_mps (unsigned n) { return evolution_table[context[n].index][2]; }
|
||||
bool SPC7110Decomp::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; }
|
||||
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 SPC7110Decomp::morton_2x8(unsigned data) {
|
||||
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
|
||||
return morton16[0][(data >> 0) & 255] + morton16[1][(data >> 8) & 255];
|
||||
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 SPC7110Decomp::morton_4x8(unsigned data) {
|
||||
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
|
||||
return morton32[0][(data >> 0) & 255] + morton32[1][(data >> 8) & 255]
|
||||
+ morton32[2][(data >> 16) & 255] + morton32[3][(data >> 24) & 255];
|
||||
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 SPC7110Decomp::reset() {
|
||||
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;
|
||||
|
@ -479,32 +486,12 @@ void SPC7110Decomp::reset() {
|
|||
decomp_buffer_length = 0;
|
||||
}
|
||||
|
||||
SPC7110Decomp::SPC7110Decomp() {
|
||||
SPC7110::Decomp::Decomp() {
|
||||
decomp_buffer = new uint8_t[decomp_buffer_size];
|
||||
reset();
|
||||
|
||||
//initialize reverse morton lookup tables
|
||||
for(unsigned i = 0; i < 256; i++) {
|
||||
#define map(x, y) (((i >> x) & 1) << y)
|
||||
//2x8-bit
|
||||
morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6)
|
||||
+ map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4);
|
||||
morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2)
|
||||
+ map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0);
|
||||
//4x8-bit
|
||||
morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7)
|
||||
+ map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6);
|
||||
morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5)
|
||||
+ map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4);
|
||||
morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3)
|
||||
+ map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2);
|
||||
morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1)
|
||||
+ map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0);
|
||||
#undef map
|
||||
}
|
||||
}
|
||||
|
||||
SPC7110Decomp::~SPC7110Decomp() {
|
||||
SPC7110::Decomp::~Decomp() {
|
||||
delete[] decomp_buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
class SPC7110Decomp {
|
||||
class Decomp {
|
||||
public:
|
||||
uint8 read();
|
||||
void init(unsigned mode, unsigned offset, unsigned index);
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
SPC7110Decomp();
|
||||
~SPC7110Decomp();
|
||||
Decomp();
|
||||
~Decomp();
|
||||
|
||||
private:
|
||||
unsigned decomp_mode;
|
||||
|
@ -39,8 +39,6 @@ private:
|
|||
uint8 next_mps(unsigned n);
|
||||
bool toggle_invert(unsigned n);
|
||||
|
||||
unsigned morton16[2][256];
|
||||
unsigned morton32[4][256];
|
||||
unsigned morton_2x8(unsigned data);
|
||||
unsigned morton_4x8(unsigned data);
|
||||
unsigned deinterleave_2x8(unsigned data);
|
||||
unsigned deinterleave_4x8(unsigned data);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SPC7110_CPP
|
||||
|
||||
void SPC7110Decomp::serialize(serializer &s) {
|
||||
void SPC7110::Decomp::serialize(serializer &s) {
|
||||
s.integer(decomp_mode);
|
||||
s.integer(decomp_offset);
|
||||
|
||||
|
|
|
@ -1,21 +1,5 @@
|
|||
/*****
|
||||
* SPC7110 emulator - version 0.04 (2010-02-14)
|
||||
* Copyright (c) 2008-2010, byuu and neviksti
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* The software is provided "as is" and the author disclaims all warranties
|
||||
* with regard to this software including all implied warranties of
|
||||
* merchantibility and fitness, in no event shall the author be liable for
|
||||
* any special, direct, indirect, or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether in an
|
||||
* action of contract, negligence or other tortious action, arising out of
|
||||
* or in connection with the use or performance of this software.
|
||||
*****/
|
||||
|
||||
#include "decomp.hpp"
|
||||
//SPC7110 emulator - version 0.05 (2011-06-27)
|
||||
//Copyright (c) 2008-2011, byuu and neviksti
|
||||
|
||||
class SPC7110 {
|
||||
public:
|
||||
|
@ -75,7 +59,8 @@ private:
|
|||
uint8 r480b; //decompression control register
|
||||
uint8 r480c; //decompression status
|
||||
|
||||
SPC7110Decomp decomp;
|
||||
#include "decomp.hpp"
|
||||
Decomp decomp;
|
||||
|
||||
//==============
|
||||
//data port unit
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "080";
|
||||
static const char Version[] = "080.01";
|
||||
static const unsigned SerializerVersion = 21;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ struct Interface : public SNES::Interface {
|
|||
unsigned height = overscan ? 239 : 224;
|
||||
if(interlace) height <<= 1;
|
||||
data += 9 * 1024; //skip front porch
|
||||
if(pvideo_refresh) return pvideo_refresh(data, width, height);
|
||||
if(pvideo_refresh) pvideo_refresh(data, width, height);
|
||||
if(pinput_poll) pinput_poll();
|
||||
}
|
||||
|
||||
void audio_sample(uint16_t left, uint16_t right) {
|
||||
|
|
Loading…
Reference in New Issue