add homemade cd-rom ECC/EDC code

This commit is contained in:
zeromus 2012-11-15 08:03:23 +00:00
parent c5d6fad0e1
commit 2ff12a9e3a
7 changed files with 483 additions and 83 deletions

View File

@ -465,6 +465,7 @@
<Compile Include="DiscSystem\ECM.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="DiscSystem\GPL_ECM.cs" />
<Compile Include="DiscSystem\Subcode.cs">
<SubType>Code</SubType>
</Compile>

View File

@ -1,4 +1,7 @@
namespace BizHawk
//we could get a little list of crcs from here and make it clear which crc this class was for, and expose others
//http://www.ross.net/crc/download/crc_v3.txt
namespace BizHawk
{
public static class CRC32
{

View File

@ -235,12 +235,23 @@ namespace BizHawk.DiscSystem
buffer[offset + 14] = bcd_aba_frac;
//mode 1
buffer[offset + 15] = 1;
//EDC
ECM.edc_computeblock(buffer, offset+2064, buffer, offset+2064);
//calculate EDC and poke into the sector
uint edc = ECM.EDC_Calc(buffer, offset);
buffer[offset + 2064 + 0] = (byte)((edc >> 0) & 0xFF);
buffer[offset + 2064 + 1] = (byte)((edc >> 8) & 0xFF);
buffer[offset + 2064 + 2] = (byte)((edc >> 16) & 0xFF);
buffer[offset + 2064 + 3] = (byte)((edc >> 24) & 0xFF);
//intermediate
for (int i = 0; i < 8; i++) buffer[offset + 2068 + i] = 0;
//ECC
ECM.ecc_generate(buffer, offset, false, buffer, offset+2076);
ECM.ECC_Populate(buffer, offset, buffer, offset, false);
//VALIDATION - check our homemade algorithms against code derived from ECM
////EDC
//GPL_ECM.edc_validateblock(buffer, 2064, buffer, offset + 2064);
////ECC
//GPL_ECM.ecc_validate(buffer, offset, false);
//if we read the 2048 physical bytes OK, then return the complete sector
if (read == 2048)

View File

@ -1,95 +1,321 @@
//Currently, this is stolen somewhat from blargg's code. probably LGPL. I think? originally it came from mednafen, and then I think mednafen may have changed to use another.
//sorry for the confusion! it'd be nice to have some nice MIT licensed CD algorithms codes.. at least, we can keep these bullshit licensed ones here to a/b test when rewriting.
//Copyright (c) 2012 BizHawk team
//Permission is hereby granted, free of charge, to any person obtaining a copy of
//this software and associated documentation files (the "Software"), to deal in
//the Software without restriction, including without limitation the rights to
//use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
//of the Software, and to permit persons to whom the Software is furnished to do
//so, subject to the following conditions:
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
//CD-ROM ECC/EDC related algorithms
//Support for Neill Corlett's ECM file format (TBD)
//todo - ecm sometimes sets the sector address to 0 before computing the ECC. i cant find any documentation to support this.
//seems to only take effect for cd-xa (mode 2, form 1). need to ask about this or test further on a cd-xa test disc
//regarding ECC:
//it turns out mame's cdrom.c uses pretty much this exact thing, naming the tables mul2tab->ecclow and div3tab->ecchigh
//Corlett's ECM uses our same fundamental approach as well.
//I can't figure out what winUAE is doing.
namespace BizHawk.DiscSystem
{
static class ECM
{
static byte[] ecc_f_lut = new byte[256];
static byte[] ecc_b_lut = new byte[256];
static uint[] edc_lut = new uint[256];
//EDC (crc) acceleration table
static uint[] edc_table = new uint[256];
//math acceleration tables over GF(2^8) with yellowbook specified primitive polynomial 0x11D
static byte[] mul2tab = new byte[256];
static byte[] div3tab = new byte[256];
static ECM()
{
uint i, j, edc;
for(i = 0; i < 256; i++)
Prep_EDC();
Prep_ECC();
}
/// <summary>
/// calculate EDC crc tables
/// </summary>
static void Prep_EDC()
{
//14.3 of yellowbook specifies EDC crc as P(x) = (x^16 + x^15 + x^2 + 1) . (x^16 + x^2 + x + 1)
//confirmation at http://cdmagediscussion.yuku.com/topic/742/EDC-calculation
//int Pa = 0x18005;
//int Pb = 0x10007;
//long Px = 0;
//for (int i = 0; i <= 16; i++)
// for (int j = 0; j <= 16; j++)
// {
// //multiply Pa[i] * Pb[j]
// int bit = (Pa >> i) & (Pb >> j) & 1;
// //xor into result, achieving modulo-2 thereby
// Px ^= (long)bit << (i + j);
// }
//uint edc_poly = (uint)Px;
uint edc_poly = (uint)0x8001801B;
//generate the CRC table
uint reverse_edc_poly = BITREV.reverse_32(edc_poly);
for (uint i = 0; i < 256; ++i)
{
j = (uint)((i << 1) ^ (((i & 0x80) != 0) ? 0x11D : 0));
ecc_f_lut[i] = (byte)j;
ecc_b_lut[i ^ j] = (byte)i;
edc = i;
for (j = 0; j < 8; j++)
edc = (edc >> 1) ^ (((edc & 1) != 0) ? 0xD8018001 : 0);
edc_lut[i] = edc;
}
}
static uint edc_partial_computeblock(uint edc, byte[] src, int count)
{
int i = 0;
while (count-- != 0) edc = (edc >> 8) ^ edc_lut[(edc ^ (src[i++])) & 0xFF];
return edc;
}
public static void edc_computeblock(byte[] src, int count, byte[] dest, int dest_offset)
{
uint edc = edc_partial_computeblock(0, src, count);
dest[dest_offset + 0] = (byte)((edc >> 0) & 0xFF);
dest[dest_offset + 1] = (byte)((edc >> 8) & 0xFF);
dest[dest_offset + 2] = (byte)((edc >> 16) & 0xFF);
dest[dest_offset + 3] = (byte)((edc >> 24) & 0xFF);
}
static void ecc_computeblock(byte[] src, int src_offset, uint major_count, uint minor_count,uint major_mult, uint minor_inc, byte[] dest, int dest_offset)
{
uint size = major_count * minor_count;
uint major, minor;
for (major = 0; major < major_count; major++)
{
uint index = (major >> 1) * major_mult + (major & 1);
byte ecc_a = 0;
byte ecc_b = 0;
for (minor = 0; minor < minor_count; minor++)
uint crc = i;
for (int j = 8; j > 0; --j)
{
byte temp = src[src_offset+index];
index += minor_inc;
if (index >= size) index -= size;
ecc_a ^= temp;
ecc_b ^= temp;
ecc_a = ecc_f_lut[ecc_a];
//System.Console.WriteLine("{0} {1}", ecc_a, ecc_b);
if ((crc & 1) == 1)
crc = ((crc >> 1) ^ reverse_edc_poly);
else
crc >>= 1;
}
ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b];
dest[dest_offset + major] = ecc_a;
dest[dest_offset + major + major_count] = (byte)(ecc_a ^ ecc_b);
edc_table[i] = crc;
}
}
public unsafe static void ecc_generate(byte[] sector, int sector_offset, bool zeroaddress, byte[] dest, int dest_offset)
/// <summary>
/// calculate math lookup tables for ECC calculations.
/// </summary>
static void Prep_ECC()
{
byte address0=0,address1=0,address2=0,address3=0;
//byte i;
/* Save the address and zero it out */
if(zeroaddress)
{
address0 = sector[sector_offset + 12 + 0]; sector[sector_offset + 12 + 0] = 0;
address1 = sector[sector_offset + 12 + 1]; sector[sector_offset + 12 + 1] = 0;
address2 = sector[sector_offset + 12 + 2]; sector[sector_offset + 12 + 2] = 0;
address3 = sector[sector_offset + 12 + 3]; sector[sector_offset + 12 + 3] = 0;
}
/* Compute ECC P code */
ecc_computeblock(sector, sector_offset + 0xC, 86, 24, 2, 86, dest, dest_offset);
/* Compute ECC Q code */
ecc_computeblock(sector, sector_offset + 0xC, 52, 43, 86, 88, dest, dest_offset+172);
/* Restore the address */
if (zeroaddress)
{
sector[sector_offset + 12 + 0] = address0;
sector[sector_offset + 12 + 3] = address1;
sector[sector_offset + 12 + 2] = address2;
sector[sector_offset + 12 + 1] = address3;
}
}
}
//create a table implementing f(i) = i*2
for (int i = 0; i < 256; i++)
{
int n = i * 2;
int b = n & 0xFF;
if (n > 0xFF) b ^= 0x1D; //primitive polynomial x^8 + x^4 + x^3 + x^2 + 1 -> 0x11D
mul2tab[i] = (byte)b;
}
}
//(here is a more straightforward way of doing it, just to check)
//byte[] mul2tab_B = new byte[256];
//for (int i = 1; i < 256; i++)
// mul2tab_B[i] = FFUtil.gf_mul((byte)i, (byte)2);
////(make sure theyre the same)
//for (int i = 0; i < 256; i++)
// System.Diagnostics.Debug.Assert(mul2tab[i] == mul2tab_B[i]);
//create a table implementing f(i) = i/3
for (int i = 0; i < 256; i++)
{
byte x1 = (byte)i;
byte x2 = mul2tab[i];
byte x3 = (byte)(x2 ^ x1); //2x + x = 3x
//instead of dividing 1/3 we write the table backwards since its the inverse of multiplying by 3
//this idea was taken from Corlett's techniques; I know not from whence they came.
div3tab[x3] = x1;
}
//(here is a more straightforward way of doing it, just to check)
//byte[] div3tab_B = new byte[256];
//for (int i = 0; i < 256; i++)
// div3tab_B[i] = FFUtil.gf_div((byte)i, 3);
////(make sure theyre the same)
//for (int i = 0; i < 256; i++)
// System.Diagnostics.Debug.Assert(div3tab[i] == div3tab_B[i]);
}
/// <summary>
/// Calculates ECC parity values for the specified data
/// see annex A of yellowbook
/// </summary>
public static void CalcECC(byte[] data, int base_offset, int addr_offset, int addr_add, int todo, out byte p0, out byte p1)
{
//let's take the P parity as an example. Q parity will differ by being a (45, 43) code instead of the (25, 23) illustrated here.
//
//we're supposed to multiply [ [ 1 1 1 ] [a^25 a^24 a^23 ..] ] by [ [d0] [d1] [d2] ..] and get 0
//where a is the primitive element a=2 and d0 is data[0]
//this multiplication yields a matrix equation:
//[ [d0 + d1 + d2] [d0*a^25 + d1*a^24 + d2*a^23] ] = [ [0] [0] ]
//so now we have equations:
//(d0 + d1 + d2 ..) + p0 + p1 = 0
//(d0*a^25 + d1*a^24 + d2*a^23 ..) + p0*a + p1 = 0
//lets rename these series expressions for convenience to add_accum and pow_accum, respectively. so we'd have:
//add_accum + p0 + p1 = 0
//(pow_accum + p0) * 2 + p1 = 0
//
//we can get pow_accum in iterations of multiplying by 2 and adding..
//
//I.
//pow_accum = d0 [add]
//pow_accum = d0*2 [mul]
//II.
//pow_accum = d0*2 + d1 [add]
//pow_accum = (d0*2 + d1)*2 [mul]
//
//.. and we can get add_accum in the obvious way in iterations by adding.
//
//now all that remains is to solve the equations:
//(pow_accum + p0) * 2 + p1 = 0
//(pow_accum + p0) * 2 + add_accum + p0 = 0
//2*pow_accum + 2*p0 + add_accum + p0 = 0
//3*p0 + p0 = -2*pow_accum - add_accum
//3*p0 = (2*pow_accum) ^ add_accum
//p0 = ((2*pow_accum) ^ add_accum) / 3
//..and..
//add_accum + p0 + p1 = 0
//p1 = - p0 - add_accum
//p1 = p0 ^ add_accum
byte pow_accum = 0;
byte add_accum = 0;
for (int i = 0; i < todo; i++)
{
addr_offset %= (1118 * 2); //modulo addressing is irrelevant for P-parity calculation but comes into play for Q-parity
byte d = data[base_offset + addr_offset];
addr_offset += addr_add;
add_accum ^= d;
pow_accum ^= d;
pow_accum = mul2tab[pow_accum];
}
p0 = div3tab[mul2tab[pow_accum] ^ add_accum];
p1 = (byte)(p0 ^ add_accum);
}
/// <summary>
/// calculates EDC checksum for bytes [0,2063] of a sector located at (offset(
/// see section 14.3 of yellowbook
/// </summary>
public static uint EDC_Calc(byte[] data, int offset)
{
uint crc = 0;
for (int i = 0; i <= 2063; i++)
{
byte b = data[offset + i];
int entry = ((int)crc ^ b) & 0xFF;
crc = edc_table[entry] ^ (crc >> 8);
}
return crc;
}
/// <summary>
/// returns the address from a sector. useful for saving it before zeroing it for ECC calculations
/// </summary>
static uint GetSectorAddress(byte[] sector, int sector_offset)
{
return (uint)(
(sector[sector_offset + 12 + 0] << 0)
| (sector[sector_offset + 12 + 1] << 8)
| (sector[sector_offset + 12 + 2] << 16)
| (sector[sector_offset + 12 + 3] << 24));
}
/// <summary>
/// sets the address for a sector. useful for restoring it after zeroing it for ECC calculations
/// </summary>
static void SetSectorAddress(byte[] sector, int sector_offset, uint address)
{
sector[sector_offset + 12 + 0] = (byte)((address >> 0) & 0xFF);
sector[sector_offset + 12 + 1] = (byte)((address >> 8) & 0xFF);
sector[sector_offset + 12 + 2] = (byte)((address >> 16) & 0xFF);
sector[sector_offset + 12 + 3] = (byte)((address >> 24) & 0xFF);
}
/// <summary>
/// populates a sector with valid ECC information.
/// it is safe to supply the same array for sector and dest.
/// </summary>
public static void ECC_Populate(byte[] src, int src_offset, byte[] dest, int dest_offset, bool zeroSectorAddress)
{
//save the old sector address, so we can restore it later. SOMETIMES ECC is supposed to be calculated without it? see TODO
uint address = GetSectorAddress(src, src_offset);
if (zeroSectorAddress) SetSectorAddress(src, src_offset, 0);
//all further work takes place relative to offset 12 in the sector
src_offset += 12;
dest_offset += 12;
//calculate P parity for 86 columns (twice 43 word-columns)
byte parity0, parity1;
for (int col = 0; col < 86; col++)
{
int offset = col;
CalcECC(src, src_offset, offset, 86, 24, out parity0, out parity1);
//store the parities in the sector; theyre read for the Q parity calculations
dest[dest_offset + 1032 * 2 + col] = parity0;
dest[dest_offset + 1032 * 2 + col + 43 * 2] = parity1;
}
//calculate Q parity for 52 diagonals (twice 26 word-diagonals)
//modulo addressing is taken care of in CalcECC
for (int d = 0; d < 26; d++)
{
for (int w = 0; w < 2; w++)
{
int offset = d * 86 + w;
CalcECC(src, src_offset, offset, 88, 43, out parity0, out parity1);
//store the parities in the sector; thats where theyve got to go anyway
dest[dest_offset + 1118 * 2 + d * 2 + w] = parity0;
dest[dest_offset + 1118 * 2 + d * 2 + w + 26 * 2] = parity1;
}
}
//unadjust the offset back to an absolute sector address, which SetSectorAddress expects
src_offset -= 12;
SetSectorAddress(src, src_offset, address);
}
///// <summary>
///// Finite Field math helpers. Adapted from: http://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders
///// Only used by alternative implementations of ECM techniques
///// </summary>
//static class FFUtil
//{
// public static byte gf_div(byte x, byte y)
// {
// if (y == 0)
// return 0; //? error ?
// if (x == 0)
// return 0;
// int q = gf_log[x] + 255 - gf_log[y];
// return gf_exp[q];
// }
// public static byte gf_mul(byte x, byte y)
// {
// if (x == 0 || y == 0)
// return 0;
// return gf_exp[gf_log[x] + gf_log[y]];
// }
// static byte[] gf_exp = new byte[512];
// static byte[] gf_log = new byte[256];
// static FFUtil()
// {
// for (int i = 0; i < 512; i++) gf_exp[i] = 1;
// for (int i = 0; i < 256; i++) gf_log[i] = 0;
// int x = 1;
// for (int i = 1; i < 255; i++)
// {
// x <<= 1;
// if ((x & 0x100) != 0)
// x ^= 0x11d; //yellowbook specified primitive polynomial
// gf_exp[i] = (byte)x;
// gf_log[x] = (byte)i;
// }
// for (int i = 255; i < 512; i++)
// gf_exp[i] = gf_exp[(byte)(i - 255)];
// }
//} //static class FFUtil
} //static class ECM
}

View File

@ -0,0 +1,116 @@
////-------------------
////WARNING GPL CODE
////-------------------
////
////this is stolen somewhat from neill corlett's code. almost certainly some kind of GPL. originally it came from mednafen, and then I think mednafen may have changed to use another. sorry for the confusion!
////
////it's kept in this project so that we can readily a/b test it against new algorithms
//using System.Diagnostics;
//namespace BizHawk.DiscSystem
//{
// public static class GPL_ECM
// {
// static byte[] ecc_f_lut = new byte[256];
// static byte[] ecc_b_lut = new byte[256];
// static uint[] edc_lut = new uint[256];
// static GPL_ECM()
// {
// uint i, j, edc;
// for (i = 0; i < 256; i++)
// {
// j = (uint)((i << 1) ^ (((i & 0x80) != 0) ? 0x11D : 0));
// ecc_f_lut[i] = (byte)j;
// ecc_b_lut[i ^ j] = (byte)i;
// edc = i;
// for (j = 0; j < 8; j++)
// edc = (edc >> 1) ^ (((edc & 1) != 0) ? 0xD8018001 : 0);
// edc_lut[i] = edc;
// }
// }
// public static uint edc_partial_computeblock(uint edc, byte[] src, int count)
// {
// int i = 0;
// while (count-- != 0) edc = (edc >> 8) ^ edc_lut[(edc ^ (src[i++])) & 0xFF];
// return edc;
// }
// public static void edc_computeblock(byte[] src, int count, byte[] dest, int dest_offset)
// {
// uint edc = edc_partial_computeblock(0, src, count);
// dest[dest_offset + 0] = (byte)((edc >> 0) & 0xFF);
// dest[dest_offset + 1] = (byte)((edc >> 8) & 0xFF);
// dest[dest_offset + 2] = (byte)((edc >> 16) & 0xFF);
// dest[dest_offset + 3] = (byte)((edc >> 24) & 0xFF);
// }
// public static void edc_validateblock(byte[] src, int count, byte[] dest, int dest_offset)
// {
// uint edc = edc_partial_computeblock(0, src, count);
// Debug.Assert(dest[dest_offset + 0] == (byte)((edc >> 0) & 0xFF));
// Debug.Assert(dest[dest_offset + 1] == (byte)((edc >> 8) & 0xFF));
// Debug.Assert(dest[dest_offset + 2] == (byte)((edc >> 16) & 0xFF));
// Debug.Assert(dest[dest_offset + 3] == (byte)((edc >> 24) & 0xFF));
// }
// public static void ecc_validateblock(byte[] src, int src_offset, uint major_count, uint minor_count, uint major_mult, uint minor_inc, byte[] dest, int dest_offset)
// {
// uint size = major_count * minor_count;
// uint major, minor;
// for (major = 0; major < major_count; major++)
// {
// uint index = (major >> 1) * major_mult + (major & 1);
// byte ecc_a = 0;
// byte ecc_b = 0;
// for (minor = 0; minor < minor_count; minor++)
// {
// byte temp = src[src_offset + index];
// if ((major >> 1) * major_mult + (major & 1) == 12 && minor_inc == 86)
// System.Console.WriteLine(temp);
// index += minor_inc;
// if (index >= size) index -= size;
// ecc_a ^= temp;
// ecc_b ^= temp;
// ecc_a = ecc_f_lut[ecc_a];
// }
// ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b];
// Debug.Assert(dest[dest_offset + major] == ecc_a);
// Debug.Assert(dest[dest_offset + major + major_count] == (byte)(ecc_a ^ ecc_b));
// }
// }
// public unsafe static void ecc_validate(byte[] sector, int sector_offset, bool zeroaddress)
// {
// byte[] dest = sector;
// int dest_offset = sector_offset+2076;
// byte address0 = 0, address1 = 0, address2 = 0, address3 = 0;
// //byte i;
// /* Save the address and zero it out */
// if (zeroaddress)
// {
// address0 = sector[sector_offset + 12 + 0]; sector[sector_offset + 12 + 0] = 0;
// address1 = sector[sector_offset + 12 + 1]; sector[sector_offset + 12 + 1] = 0;
// address2 = sector[sector_offset + 12 + 2]; sector[sector_offset + 12 + 2] = 0;
// address3 = sector[sector_offset + 12 + 3]; sector[sector_offset + 12 + 3] = 0;
// }
// /* Compute ECC P code */
// ecc_validateblock(sector, sector_offset + 0xC, 86, 24, 2, 86, dest, dest_offset);
// /* Compute ECC Q code */
// ecc_validateblock(sector, sector_offset + 0xC, 52, 43, 86, 88, dest, dest_offset + 172);
// /* Restore the address */
// if (zeroaddress)
// {
// sector[sector_offset + 12 + 0] = address0;
// sector[sector_offset + 12 + 3] = address1;
// sector[sector_offset + 12 + 2] = address2;
// sector[sector_offset + 12 + 1] = address3;
// }
// }
// }
//}

View File

@ -0,0 +1,35 @@
//lets leave some notes here until we've rewritten every possible thing -- error recovery, ECM file format, ISO filesystem, etc.
//here is a braindump of urls and stuff for future reference
//check this for some iso stuff but seems like it ripped off corlett's code
//http://lioneditor.googlecode.com/svn/trunk/utils/isopatcherv05/src/
//http://code.ohloh.net/file?fid=185llKM04w3QCqwC2MdFgtUiQ94&cid=yPMRq_HKxUg&s=ecc_computeblock%28pSector%20%2B%200xC%2C%2052%2C%2043%2C%2086%2C%2088%2C%20pSector%20%2B%200x8C8%29&mp=1&ml=1&me=1&md=1&browser=Default#L106
//more gpl edc/ecc
//http://code.ohloh.net/file?fid=BEZeY2fWALJKXTgY3Oe9J988ubQ&cid=Xkpw3SKt7K8&s=edc%20ecc%20&pp=0&fl=C&ff=1&filterChecked=true&mp=1&ml=1&me=1&md=1&browser=Default#L13
//still more.. comes from lxdream, which takes its code from cdrkit. cdrkit is gpl
//http://code.ohloh.net/file?fid=asMhpC6ygBi47pIYaxYwhXJFptI&cid=T6ljN87aG7M&s=&browser=Default&pp=0&fl=NonCode&fl=C&fl=C%2B%2B&ff=1&mp=1&ml=1&me=1&md=1&filterChecked=true#L0
//cdemu/cdrtools/dvdrtools/cdkit maybe useful libraries to reference but all gpl?
//cdrdao is GPL as well
//cdrtools is some weird license CDDL
//cdrkit was forked from the last GPL version of cdrtools. cdrkit is definitely gpl
//libedc was part of cdrtools; now part of cdrkit too when it forked. but it is GPL
//dvdisaster is GPL too
//one more thing http://www.gnu.org/software/libcdio/libcdio.html
//entertaining debacle
//https://bugzilla.novell.com/show_bug.cgi?id=672491#c7
//this
//https://github.com/tonioni/WinUAE/blob/master/cdrom.cpp
//references this
//http://www.ross.net/crc/download/crc_v3.txt
//this code in mednafen's lec.cpp calculates the reed solomon crap. port it to c# and then a/b test against it
//Gf8_Q_Coeffs_Results_01
//assorted other helpful urls
//http://www.cs.utsa.edu/~wagner/laws/FFM.html
//http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/reedsolomon/reed_solomon_codes.html
//http://en.wikipedia.org/wiki/Finite_field_arithmetic

View File

@ -1054,6 +1054,14 @@ namespace BizHawk
byte_8[j++] = (byte)(byte_8[i] + a);
}
}
public static uint reverse_32(uint v)
{
return (uint)((byte_8[v & 0xff] << 24) |
(byte_8[(v >> 8) & 0xff] << 16) |
(byte_8[(v >> 16) & 0xff] << 8) |
(byte_8[(v >> 24) & 0xff]));
}
}
/// <summary>