Backport CD-ROM code

This commit is contained in:
twinaphex 2016-08-07 15:38:04 +02:00
parent 959b7218a9
commit 7aaa4ed614
26 changed files with 1619 additions and 1477 deletions

View File

@ -76,15 +76,17 @@ ifneq ($(HAVE_GRIFFIN),1)
SOURCES_CXX += $(MEDNAFEN_DIR)/cdrom/CDAccess.cpp \
$(MEDNAFEN_DIR)/cdrom/CDAccess_Image.cpp \
$(MEDNAFEN_DIR)/cdrom/CDAccess_CCD.cpp \
$(MEDNAFEN_DIR)/cdrom/CDUtility.cpp \
$(MEDNAFEN_DIR)/cdrom/lec.cpp \
$(MEDNAFEN_DIR)/cdrom/SimpleFIFO.cpp \
$(MEDNAFEN_DIR)/cdrom/audioreader.cpp \
$(MEDNAFEN_DIR)/cdrom/galois.cpp \
$(MEDNAFEN_DIR)/cdrom/recover-raw.cpp \
$(MEDNAFEN_DIR)/cdrom/l-ec.cpp \
$(MEDNAFEN_DIR)/cdrom/crc32.cpp \
$(MEDNAFEN_DIR)/cdrom/cdromif.cpp
SOURCES_C += \
$(MEDNAFEN_DIR)/cdrom/CDUtility.c \
$(MEDNAFEN_DIR)/cdrom/lec.c \
$(MEDNAFEN_DIR)/cdrom/galois.c \
$(MEDNAFEN_DIR)/cdrom/recover-raw.c \
$(MEDNAFEN_DIR)/cdrom/l-ec.c \
$(MEDNAFEN_DIR)/cdrom/edc_crc32.c
endif
FLAGS += -DNEED_CD
endif

View File

@ -298,7 +298,7 @@ static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
};
uint8 sector_buffer[2048];
CDIF *cdiface = (*CDInterfaces)[0];
CDUtility::TOC toc;
TOC toc;
bool ret = FALSE;
memset(sector_buffer, 0, sizeof(sector_buffer));
@ -970,7 +970,7 @@ MDFNGI *MDFNI_LoadCD(const char *force_module, const char *devicename)
MDFN_indent(1);
for(unsigned i = 0; i < CDInterfaces.size(); i++)
{
CDUtility::TOC toc;
TOC toc;
CDInterfaces[i]->ReadTOC(&toc);
@ -1251,7 +1251,7 @@ void retro_init(void)
log_cb = NULL;
#ifdef NEED_CD
CDUtility::CDUtility_Init();
CDUtility_Init();
#endif
const char *dir = NULL;

View File

@ -22,12 +22,6 @@
#include "CDAccess_Image.h"
#include "CDAccess_CCD.h"
#ifdef HAVE_LIBCDIO
#include "CDAccess_Physical.h"
#endif
using namespace CDUtility;
CDAccess::CDAccess()
{

View File

@ -14,7 +14,7 @@ class CDAccess
virtual void Read_Raw_Sector(uint8 *buf, int32 lba) = 0;
virtual void Read_TOC(CDUtility::TOC *toc) = 0;
virtual void Read_TOC(TOC *toc) = 0;
virtual bool Is_Physical(void) throw() = 0;

View File

@ -24,8 +24,6 @@
#include <limits.h>
#include <map>
using namespace CDUtility;
static void MDFN_strtoupper(std::string &str)
{
const size_t len = str.length();
@ -502,7 +500,7 @@ void CDAccess_CCD::Read_Raw_Sector(uint8 *buf, int32 lba)
}
void CDAccess_CCD::Read_TOC(CDUtility::TOC *toc)
void CDAccess_CCD::Read_TOC(TOC *toc)
{
*toc = tocd;
}

View File

@ -30,7 +30,7 @@ class CDAccess_CCD : public CDAccess
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
virtual void Read_TOC(CDUtility::TOC *toc);
virtual void Read_TOC(TOC *toc);
virtual bool Is_Physical(void) throw();
@ -46,5 +46,5 @@ class CDAccess_CCD : public CDAccess
Stream* img_stream;
Stream* sub_stream;
size_t img_numsectors;
CDUtility::TOC tocd;
TOC tocd;
};

View File

@ -49,8 +49,6 @@
#include <map>
using namespace CDUtility;
enum
{
CDRF_SUBM_NONE = 0,
@ -1119,7 +1117,7 @@ void CDAccess_Image::MakeSubPQ(int32 lba, uint8 *SubPWBuf)
void CDAccess_Image::Read_TOC(TOC *toc)
{
toc->Clear();
TOC_Clear(toc);
toc->first_track = FirstTrack;
toc->last_track = FirstTrack + NumTracks - 1;

View File

@ -68,7 +68,7 @@ class CDAccess_Image : public CDAccess
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
virtual void Read_TOC(CDUtility::TOC *toc);
virtual void Read_TOC(TOC *toc);
virtual bool Is_Physical(void) throw();

324
mednafen/cdrom/CDUtility.c Normal file
View File

@ -0,0 +1,324 @@
/* Mednafen - Multi-system Emulator
*
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "CDUtility.h"
#include "edc_crc32.h"
#include "galois.h"
#include "l-ec.h"
#include "recover-raw.h"
#include "lec.h"
#include <assert.h>
/* lookup table for crc calculation */
static uint16_t subq_crctab[256] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
static uint8_t cdutil_scramble_table[2352 - 12];
static bool CDUtility_Inited = false;
static void InitScrambleTable(void)
{
unsigned i, b;
unsigned cv = 1;
for(i = 12; i < 2352; i++)
{
unsigned char z = 0;
for(b = 0; b < 8; b++)
{
z |= (cv & 1) << b;
int feedback = ((cv >> 1) & 1) ^ (cv & 1);
cv = (cv >> 1) | (feedback << 14);
}
cdutil_scramble_table[i - 12] = z;
}
}
void CDUtility_Init(void)
{
if(!CDUtility_Inited)
{
Init_LEC_Correct();
InitScrambleTable();
lec_tables_init();
CDUtility_Inited = true;
}
}
void encode_mode0_sector(uint32_t aba, uint8_t *sector_data)
{
CDUtility_Init();
lec_encode_mode0_sector(aba, sector_data);
}
void encode_mode1_sector(uint32_t aba, uint8_t *sector_data)
{
CDUtility_Init();
lec_encode_mode1_sector(aba, sector_data);
}
void encode_mode2_sector(uint32_t aba, uint8_t *sector_data)
{
CDUtility_Init();
lec_encode_mode2_sector(aba, sector_data);
}
void encode_mode2_form1_sector(uint32_t aba, uint8_t *sector_data)
{
CDUtility_Init();
lec_encode_mode2_form1_sector(aba, sector_data);
}
void encode_mode2_form2_sector(uint32_t aba, uint8_t *sector_data)
{
CDUtility_Init();
lec_encode_mode2_form2_sector(aba, sector_data);
}
bool edc_check(const uint8_t *sector_data, bool xa)
{
CDUtility_Init();
return(CheckEDC(sector_data, xa));
}
bool edc_lec_check_and_correct(uint8_t *sector_data, bool xa)
{
CDUtility_Init();
return(ValidateRawSector(sector_data, xa));
}
bool subq_check_checksum(const uint8_t *SubQBuf)
{
unsigned i;
uint16_t crc = 0;
uint16_t stored_crc = SubQBuf[0xA] << 8;
stored_crc |= SubQBuf[0xB];
for(i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
crc = ~crc;
return(crc == stored_crc);
}
void subq_generate_checksum(uint8_t *buf)
{
unsigned i;
uint16_t crc = 0;
for(i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
/* Checksum */
buf[0xa] = ~(crc >> 8);
buf[0xb] = ~(crc);
}
void subq_deinterleave(const uint8_t *SubPWBuf, uint8_t *qbuf)
{
unsigned i;
memset(qbuf, 0, 0xC);
for(i = 0; i < 96; i++)
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
}
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
void subpw_deinterleave(const uint8_t *in_buf, uint8_t *out_buf)
{
unsigned ch, i;
assert(in_buf != out_buf);
memset(out_buf, 0, 96);
for(ch = 0; ch < 8; ch++)
{
for(i = 0; i < 96; i++)
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
}
}
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
void subpw_interleave(const uint8_t *in_buf, uint8_t *out_buf)
{
unsigned d, bitpoodle, ch;
assert(in_buf != out_buf);
for(d = 0; d < 12; d++)
{
for(bitpoodle = 0; bitpoodle < 8; bitpoodle++)
{
uint8_t rawb = 0;
for(ch = 0; ch < 8; ch++)
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
out_buf[(d << 3) + bitpoodle] = rawb;
}
}
}
// NOTES ON LEADOUT AREA SYNTHESIS
//
// I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
// and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
// data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).
//
void subpw_synth_leadout_lba(const struct TOC *toc, const int32_t lba, uint8_t* SubPWBuf)
{
unsigned i;
uint8_t buf[0xC];
uint32_t lba_relative = lba - toc->tracks[100].lba;
uint32_t f = (lba_relative % 75);
uint32_t s = ((lba_relative / 75) % 60);
uint32_t m = (lba_relative / 75 / 60);
uint32_t fa = (lba + 150) % 75;
uint32_t sa = ((lba + 150) / 75) % 60;
uint32_t ma = ((lba + 150) / 75 / 60);
uint8_t adr = 0x1; // Q channel data encodes position
uint8_t control = toc->tracks[100].control;
if (toc->tracks[toc->last_track].valid)
control |= toc->tracks[toc->last_track].control & 0x4;
else if (toc->disc_type == DISC_TYPE_CD_I)
control |= 0x4;
memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4);
buf[1] = 0xAA;
buf[2] = 0x01;
/* Track relative MSF address */
buf[3] = U8_to_BCD(m);
buf[4] = U8_to_BCD(s);
buf[5] = U8_to_BCD(f);
buf[6] = 0; /* Zerroooo */
/* Absolute MSF address */
buf[7] = U8_to_BCD(ma);
buf[8] = U8_to_BCD(sa);
buf[9] = U8_to_BCD(fa);
subq_generate_checksum(buf);
for(i = 0; i < 96; i++)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
}
void synth_leadout_sector_lba(uint8_t mode, const struct TOC *toc, const int32_t lba, uint8_t* out_buf)
{
memset(out_buf, 0, 2352 + 96);
subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
if(out_buf[2352 + 1] & 0x40)
{
if(mode == 0xFF)
{
if(toc->disc_type == DISC_TYPE_CD_XA || toc->disc_type == DISC_TYPE_CD_I)
mode = 0x02;
else
mode = 0x01;
}
switch(mode)
{
default:
encode_mode0_sector(LBA_to_ABA(lba), out_buf);
break;
case 0x01:
encode_mode1_sector(LBA_to_ABA(lba), out_buf);
break;
case 0x02:
out_buf[12 + 6] = 0x20;
out_buf[12 + 10] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
break;
}
}
}
/* ISO/IEC 10149:1995 (E): 20.2 */
#if 0
/* TODO/FIXME - missing functions */
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf);
void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf);
#endif
void scrambleize_data_sector(uint8_t *sector_data)
{
unsigned i;
for(i = 12; i < 2352; i++)
sector_data[i] ^= cdutil_scramble_table[i - 12];
}

View File

@ -1,322 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../mednafen.h"
#include "CDUtility.h"
#include "dvdisaster.h"
#include "lec.h"
#include <assert.h>
// Kill_LEC_Correct();
namespace CDUtility
{
// lookup table for crc calculation
static uint16 subq_crctab[256] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
static uint8 scramble_table[2352 - 12];
static bool CDUtility_Inited = false;
static void InitScrambleTable(void)
{
unsigned cv = 1;
for(unsigned i = 12; i < 2352; i++)
{
unsigned char z = 0;
for(int b = 0; b < 8; b++)
{
z |= (cv & 1) << b;
int feedback = ((cv >> 1) & 1) ^ (cv & 1);
cv = (cv >> 1) | (feedback << 14);
}
scramble_table[i - 12] = z;
}
//for(int i = 0; i < 2352 - 12; i++)
// printf("0x%02x, ", scramble_table[i]);
}
void CDUtility_Init(void)
{
if(!CDUtility_Inited)
{
Init_LEC_Correct();
InitScrambleTable();
CDUtility_Inited = true;
}
}
void encode_mode0_sector(uint32 aba, uint8 *sector_data)
{
CDUtility_Init();
lec_encode_mode0_sector(aba, sector_data);
}
void encode_mode1_sector(uint32 aba, uint8 *sector_data)
{
CDUtility_Init();
lec_encode_mode1_sector(aba, sector_data);
}
void encode_mode2_sector(uint32 aba, uint8 *sector_data)
{
CDUtility_Init();
lec_encode_mode2_sector(aba, sector_data);
}
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
{
CDUtility_Init();
lec_encode_mode2_form1_sector(aba, sector_data);
}
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
{
CDUtility_Init();
lec_encode_mode2_form2_sector(aba, sector_data);
}
bool edc_check(const uint8 *sector_data, bool xa)
{
CDUtility_Init();
return(CheckEDC(sector_data, xa));
}
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
{
CDUtility_Init();
return(ValidateRawSector(sector_data, xa));
}
bool subq_check_checksum(const uint8 *SubQBuf)
{
uint16 crc = 0;
uint16 stored_crc = 0;
stored_crc = SubQBuf[0xA] << 8;
stored_crc |= SubQBuf[0xB];
for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
crc = ~crc;
return(crc == stored_crc);
}
void subq_generate_checksum(uint8 *buf)
{
uint16 crc = 0;
for(int i = 0; i < 0xA; i++)
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
// Checksum
buf[0xa] = ~(crc >> 8);
buf[0xb] = ~(crc);
}
void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
{
memset(qbuf, 0, 0xC);
for(int i = 0; i < 96; i++)
{
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
}
}
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf)
{
assert(in_buf != out_buf);
memset(out_buf, 0, 96);
for(unsigned ch = 0; ch < 8; ch++)
{
for(unsigned i = 0; i < 96; i++)
{
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
}
}
}
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
{
assert(in_buf != out_buf);
for(unsigned d = 0; d < 12; d++)
{
for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
{
uint8 rawb = 0;
for(unsigned ch = 0; ch < 8; ch++)
{
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
}
out_buf[(d << 3) + bitpoodle] = rawb;
}
}
}
// NOTES ON LEADOUT AREA SYNTHESIS
//
// I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
// and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
// data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).
//
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
{
uint8 buf[0xC];
uint32 lba_relative;
uint32 ma, sa, fa;
uint32 m, s, f;
lba_relative = lba - toc.tracks[100].lba;
f = (lba_relative % 75);
s = ((lba_relative / 75) % 60);
m = (lba_relative / 75 / 60);
fa = (lba + 150) % 75;
sa = ((lba + 150) / 75) % 60;
ma = ((lba + 150) / 75 / 60);
uint8 adr = 0x1; // Q channel data encodes position
uint8 control = (toc.tracks[toc.last_track].control & 0x4) | toc.tracks[100].control;
memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4);
buf[1] = 0xAA;
buf[2] = 0x01;
// Track relative MSF address
buf[3] = U8_to_BCD(m);
buf[4] = U8_to_BCD(s);
buf[5] = U8_to_BCD(f);
buf[6] = 0; // Zerroooo
// Absolute MSF address
buf[7] = U8_to_BCD(ma);
buf[8] = U8_to_BCD(sa);
buf[9] = U8_to_BCD(fa);
subq_generate_checksum(buf);
for(int i = 0; i < 96; i++)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
}
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf)
{
memset(out_buf, 0, 2352 + 96);
subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
if((toc.tracks[toc.last_track].control | toc.tracks[100].control) & 0x4)
{
switch(mode)
{
default:
encode_mode0_sector(LBA_to_ABA(lba), out_buf);
break;
case 0x01:
encode_mode1_sector(LBA_to_ABA(lba), out_buf);
break;
case 0x02:
out_buf[18] = 0x20;
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
break;
}
}
}
#if 0
bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output)
{
assert(subq_check_checksum(subq_input));
subq_generate_checksum(subq_output);
}
#endif
void scrambleize_data_sector(uint8 *sector_data)
{
for(unsigned i = 12; i < 2352; i++)
sector_data[i] ^= scramble_table[i - 12];
}
}

View File

@ -1,225 +1,233 @@
#ifndef __MDFN_CDROM_CDUTILITY_H
#define __MDFN_CDROM_CDUTILITY_H
namespace CDUtility
#include <stdint.h>
#include <string.h>
#include <boolean.h>
#include <retro_inline.h>
#ifdef __cplusplus
extern "C" {
#endif
enum
{
// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
// It will also be called automatically if needed for the first time a function in this namespace that requires
// the initialization function to be called is called, for potential
// usage in constructors of statically-declared objects.
void CDUtility_Init(void);
ADR_NOQINFO = 0x00,
ADR_CURPOS = 0x01,
ADR_MCN = 0x02,
ADR_ISRC = 0x03
};
// Quick definitions here:
//
// ABA - Absolute block address, synonymous to absolute MSF
// aba = (m_a * 60 * 75) + (s_a * 75) + f_a
//
// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
// lba = aba - 150
struct TOC_Track
{
uint8_t adr;
uint8_t control;
uint32_t lba;
bool valid; /* valid/present; oh CD-i... */
};
// SubQ control field flags.
enum
{
SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
SUBQ_CTRLF_DATA = 0x04, // Data track.
SUBQ_CTRLF_4CH = 0x08 // 4-channel CD-DA.
};
enum
{
ADR_NOQINFO = 0x00,
ADR_CURPOS = 0x01,
ADR_MCN = 0x02,
ADR_ISRC = 0x03
};
enum
{
DISC_TYPE_CDDA_OR_M1 = 0x00,
DISC_TYPE_CD_I = 0x10,
DISC_TYPE_CD_XA = 0x20
};
struct TOC
{
uint8_t first_track;
uint8_t last_track;
uint8_t disc_type;
struct TOC_Track tracks[100 + 1];
};
struct TOC_Track
{
uint8 adr;
uint8 control;
uint32 lba;
};
// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
// It will also be called automatically if needed for the first time a function in this namespace that requires
// the initialization function to be called is called, for potential
// usage in constructors of statically-declared objects.
void CDUtility_Init(void);
// SubQ control field flags.
enum
{
SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
SUBQ_CTRLF_DATA = 0x04, // Data track.
SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.
};
// Quick definitions here:
//
// ABA - Absolute block address, synonymous to absolute MSF
// aba = (m_a * 60 * 75) + (s_a * 75) + f_a
//
// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
// lba = aba - 150
enum
{
DISC_TYPE_CDDA_OR_M1 = 0x00,
DISC_TYPE_CD_I = 0x10,
DISC_TYPE_CD_XA = 0x20
};
static INLINE void TOC_Clear(struct TOC *toc)
{
if (!toc)
return;
struct TOC
{
INLINE TOC()
{
Clear();
}
toc->first_track = 0;
toc->last_track = 0;
toc->disc_type = 0;
INLINE void Clear(void)
{
first_track = last_track = 0;
disc_type = 0;
memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
}
INLINE int FindTrackByLBA(uint32 LBA)
{
for(int32 track = first_track; track <= (last_track + 1); track++)
{
if(track == (last_track + 1))
{
if(LBA < tracks[100].lba)
return(track - 1);
}
else
{
if(LBA < tracks[track].lba)
return(track - 1);
}
}
return(0);
}
uint8 first_track;
uint8 last_track;
uint8 disc_type;
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
// Also, for convenience, tracks[last_track + 1] will always refer
// to the leadout track(even if last_track < 99, IE the leadout track details are duplicated).
};
//
// Address conversion functions.
//
static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)
{
return(f_a + 75 * s_a + 75 * 60 * m_a);
}
static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
{
*m_a = aba / 75 / 60;
*s_a = (aba - *m_a * 75 * 60) / 75;
*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
}
static INLINE int32 ABA_to_LBA(uint32 aba)
{
return(aba - 150);
}
static INLINE uint32 LBA_to_ABA(int32 lba)
{
return(lba + 150);
}
static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)
{
return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
}
static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
{
ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
}
//
// BCD conversion functions
//
static INLINE bool BCD_is_valid(uint8 bcd_number)
{
if((bcd_number & 0xF0) >= 0xA0)
return(false);
if((bcd_number & 0x0F) >= 0x0A)
return(false);
return(true);
}
static INLINE uint8 BCD_to_U8(uint8 bcd_number)
{
return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
}
static INLINE uint8 U8_to_BCD(uint8 num)
{
return( ((num / 10) << 4) + (num % 10) );
}
// should always perform the conversion, even if the bcd number is invalid.
static INLINE bool BCD_to_U8_check(uint8 bcd_number, uint8 *out_number)
{
*out_number = BCD_to_U8(bcd_number);
if(!BCD_is_valid(bcd_number))
return(false);
return(true);
}
//
// Sector data encoding functions(to full 2352 bytes raw sector).
//
// sector_data must be able to contain at least 2352 bytes.
void encode_mode0_sector(uint32 aba, uint8 *sector_data);
void encode_mode1_sector(uint32 aba, uint8 *sector_data); // 2048 bytes of user data at offset 16
void encode_mode2_sector(uint32 aba, uint8 *sector_data); // 2336 bytes of user data at offset 16
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data); // 2048+8 bytes of user data at offset 16
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data); // 2324+8 bytes of user data at offset 16
// out_buf must be able to contain 2352+96 bytes.
// "mode" is only used if(toc.tracks[100].control & 0x4)
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
//
// User data error detection and correction
//
// Check EDC of a mode 1 or mode 2 form 1 sector.
// Returns "true" if checksum is ok(matches).
// Returns "false" if checksum mismatch.
// sector_data should contain 2352 bytes of raw sector data.
bool edc_check(const uint8 *sector_data, bool xa);
// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
// Returns "true" if errors weren't detected, or they were corrected succesfully.
// Returns "false" if errors couldn't be corrected.
// sector_data should contain 2352 bytes of raw sector data.
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);
//
// Subchannel(Q in particular) functions
//
// Returns false on checksum mismatch, true on match.
bool subq_check_checksum(const uint8 *subq_buf);
// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
// in subq_buf.
void subq_generate_checksum(uint8 *subq_buf);
// Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
void subq_deinterleave(const uint8 *subpw_buf, uint8 *subq_buf);
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf);
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf);
// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
// Only valid for ADR_CURPOS.
// subq_input must pass subq_check_checksum().
// TODO
//void subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output);
// (De)Scrambles data sector.
void scrambleize_data_sector(uint8 *sector_data);
memset(toc->tracks, 0, sizeof(toc->tracks));
}
static INLINE int TOC_FindTrackByLBA(struct TOC *toc, uint32_t LBA)
{
int32_t track;
for(track = toc->first_track; track <= (toc->last_track + 1); track++)
{
if(track == (toc->last_track + 1))
{
if(LBA < toc->tracks[100].lba)
return(track - 1);
}
else
{
if(LBA < toc->tracks[track].lba)
return(track - 1);
}
}
return 0;
}
// Address conversion functions.
static INLINE uint32_t AMSF_to_ABA(int32_t m_a, int32_t s_a, int32_t f_a)
{
return(f_a + 75 * s_a + 75 * 60 * m_a);
}
static INLINE void ABA_to_AMSF(uint32_t aba, uint8_t *m_a, uint8_t *s_a, uint8_t *f_a)
{
*m_a = aba / 75 / 60;
*s_a = (aba - *m_a * 75 * 60) / 75;
*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
}
static INLINE int32_t ABA_to_LBA(uint32_t aba)
{
return(aba - 150);
}
static INLINE uint32_t LBA_to_ABA(int32_t lba)
{
return(lba + 150);
}
static INLINE int32_t AMSF_to_LBA(uint8_t m_a, uint8_t s_a, uint8_t f_a)
{
return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
}
static INLINE void LBA_to_AMSF(int32_t lba, uint8_t *m_a, uint8_t *s_a, uint8_t *f_a)
{
ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
}
//
// BCD conversion functions
//
static INLINE bool BCD_is_valid(uint8_t bcd_number)
{
if((bcd_number & 0xF0) >= 0xA0)
return(false);
if((bcd_number & 0x0F) >= 0x0A)
return(false);
return(true);
}
static INLINE uint8_t BCD_to_U8(uint8_t bcd_number)
{
return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
}
static INLINE uint8_t U8_to_BCD(uint8_t num)
{
return( ((num / 10) << 4) + (num % 10) );
}
// should always perform the conversion, even if the bcd number is invalid.
static INLINE bool BCD_to_U8_check(uint8_t bcd_number, uint8_t *out_number)
{
*out_number = BCD_to_U8(bcd_number);
if(!BCD_is_valid(bcd_number))
return(false);
return(true);
}
//
// Sector data encoding functions(to full 2352 bytes raw sector).
//
// sector_data must be able to contain at least 2352 bytes.
void encode_mode0_sector(uint32_t aba, uint8_t *sector_data);
void encode_mode1_sector(uint32_t aba, uint8_t *sector_data); // 2048 bytes of user data at offset 16
void encode_mode2_sector(uint32_t aba, uint8_t *sector_data); // 2336 bytes of user data at offset 16
void encode_mode2_form1_sector(uint32_t aba, uint8_t *sector_data); // 2048+8 bytes of user data at offset 16
void encode_mode2_form2_sector(uint32_t aba, uint8_t *sector_data); // 2324+8 bytes of user data at offset 16
// out_buf must be able to contain 2352+96 bytes.
// "mode" is only used if(toc.tracks[100].control & 0x4)
void synth_leadout_sector_lba(uint8_t mode, const struct TOC *toc, const int32_t lba, uint8_t* out_buf);
//
// User data error detection and correction
//
// Check EDC of a mode 1 or mode 2 form 1 sector.
// Returns "true" if checksum is ok(matches).
// Returns "false" if checksum mismatch.
// sector_data should contain 2352 bytes of raw sector data.
bool edc_check(const uint8_t *sector_data, bool xa);
// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
// Returns "true" if errors weren't detected, or they were corrected succesfully.
// Returns "false" if errors couldn't be corrected.
// sector_data should contain 2352 bytes of raw sector data.
bool edc_lec_check_and_correct(uint8_t *sector_data, bool xa);
//
// Subchannel(Q in particular) functions
//
// Returns false on checksum mismatch, true on match.
bool subq_check_checksum(const uint8_t *subq_buf);
// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
// in subq_buf.
void subq_generate_checksum(uint8_t *subq_buf);
// Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
void subq_deinterleave(const uint8_t *subpw_buf, uint8_t *subq_buf);
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
void subpw_deinterleave(const uint8_t *in_buf, uint8_t *out_buf);
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
void subpw_interleave(const uint8_t *in_buf, uint8_t *out_buf);
// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
// Only valid for ADR_CURPOS.
// subq_input must pass subq_check_checksum().
// TODO
//void subq_extrapolate(const uint8_t *subq_input, int32_t position_delta, uint8_t *subq_output);
// (De)Scrambles data sector.
void scrambleize_data_sector(uint8_t *sector_data);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,7 +0,0 @@
mednafen_SOURCES += cdrom/audioreader.cpp cdrom/cdromif.cpp cdrom/scsicd.cpp cdrom/pcecd.cpp
mednafen_SOURCES += cdrom/CDUtility.cpp cdrom/crc32.cpp cdrom/galois.cpp cdrom/l-ec.cpp cdrom/recover-raw.cpp
mednafen_SOURCES += cdrom/lec.cpp cdrom/CDAccess.cpp cdrom/CDAccess_Image.cpp cdrom/CDAccess_CCD.cpp
if HAVE_LIBCDIO
mednafen_SOURCES += cdrom/CDAccess_Physical.cpp
endif

View File

@ -27,8 +27,6 @@
extern retro_log_printf_t log_cb;
using namespace CDUtility;
enum
{
// Status/Error messages

View File

@ -23,8 +23,6 @@
#include <queue>
typedef CDUtility::TOC CD_TOC;
class CDIF
{
public:
@ -32,7 +30,7 @@ class CDIF
CDIF();
virtual ~CDIF();
inline void ReadTOC(CDUtility::TOC *read_target)
inline void ReadTOC(TOC *read_target)
{
*read_target = disc_toc;
}
@ -59,7 +57,7 @@ class CDIF
protected:
bool UnrecoverableError;
bool is_phys_cache;
CDUtility::TOC disc_toc;
TOC disc_toc;
bool DiscEjected;
};

130
mednafen/cdrom/edc_crc32.c Normal file
View File

@ -0,0 +1,130 @@
/* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2007 Carsten Gnoerlich.
* Project home page: http://www.dvdisaster.com
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
*
* CRC32 code based upon public domain code by Ross Williams (see notes below)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#include <stdint.h>
/***
*** EDC checksum used in CDROM sectors
***/
/*****************************************************************/
/* */
/* CRC LOOKUP TABLE */
/* ================ */
/* The following CRC lookup table was generated automagically */
/* by the Rocksoft^tm Model CRC Algorithm Table Generation */
/* Program V1.0 using the following model parameters: */
/* */
/* Width : 4 bytes. */
/* Poly : 0x8001801BL */
/* Reverse : TRUE. */
/* */
/* For more information on the Rocksoft^tm Model CRC Algorithm, */
/* see the document titled "A Painless Guide to CRC Error */
/* Detection Algorithms" by Ross Williams */
/* (ross@guest.adelaide.edu.au.). This document is likely to be */
/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
/* */
/*****************************************************************/
unsigned long edctable[256] =
{
0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
};
/*
* CDROM EDC calculation
*/
uint32_t EDCCrc32(const unsigned char *data, int len)
{
uint32_t crc = 0;
while(len--)
crc = edctable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
return crc;
}

View File

@ -0,0 +1,16 @@
#ifndef _EDC_CRC32_H
#define _EDC_CRC32_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
uint32_t EDCCrc32(const unsigned char*, int);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -22,9 +22,9 @@
* or direct your browser at http://www.gnu.org.
*/
#include "dvdisaster.h"
#include "galois-inlines.h"
#include <stdio.h>
#include <stdlib.h>
#include "galois.h"
/***
*** Galois field arithmetic.
@ -36,11 +36,10 @@
/* Initialize the Galois field tables */
GaloisTables* CreateGaloisTables(int32 gf_generator)
{
GaloisTables* CreateGaloisTables(int32_t gf_generator)
{
int32_t b,log;
GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));
int32 b,log;
/* Allocate the tables.
The encoder uses a special version of alpha_to which has the mod_fieldmax()
@ -48,10 +47,10 @@ GaloisTables* CreateGaloisTables(int32 gf_generator)
gt->gfGenerator = gf_generator;
gt->indexOf = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
gt->alphaTo = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
gt->encAlphaTo = (int32 *)calloc(2*GF_FIELDSIZE, sizeof(int32));
gt->indexOf = (int32_t *)calloc(GF_FIELDSIZE, sizeof(int32_t));
gt->alphaTo = (int32_t *)calloc(GF_FIELDSIZE, sizeof(int32_t));
gt->encAlphaTo = (int32_t *)calloc(2*GF_FIELDSIZE, sizeof(int32_t));
/* create the log/ilog values */
for(b=1, log=0; log<GF_FIELDMAX; log++)
@ -59,13 +58,13 @@ GaloisTables* CreateGaloisTables(int32 gf_generator)
gt->alphaTo[log] = b;
b = b << 1;
if(b & GF_FIELDSIZE)
b = b ^ gf_generator;
b = b ^ gf_generator;
}
if(b!=1)
{
printf("Failed to create the Galois field log tables!\n");
exit(1);
printf("Failed to create the Galois field log tables!\n");
exit(1);
}
/* we're even closed using infinity (makes things easier) */
@ -74,18 +73,21 @@ GaloisTables* CreateGaloisTables(int32 gf_generator)
gt->alphaTo[GF_ALPHA0] = 0; /* and the other way around */
for(b=0; b<2*GF_FIELDSIZE; b++)
gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
return gt;
}
void FreeGaloisTables(GaloisTables *gt)
{
if(gt->indexOf) free(gt->indexOf);
if(gt->alphaTo) free(gt->alphaTo);
if(gt->encAlphaTo) free(gt->encAlphaTo);
if(gt->indexOf)
free(gt->indexOf);
if(gt->alphaTo)
free(gt->alphaTo);
if(gt->encAlphaTo)
free(gt->encAlphaTo);
free(gt);
free(gt);
}
/***
@ -94,11 +96,13 @@ void FreeGaloisTables(GaloisTables *gt)
*/
ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
int32 first_consecutive_root,
int32 prim_elem,
int nroots_in)
{ ReedSolomonTables *rt = (ReedSolomonTables *)calloc(1, sizeof(ReedSolomonTables));
int32 i,j,root;
int32_t first_consecutive_root,
int32_t prim_elem,
int nroots_in)
{
int32_t i,j,root;
ReedSolomonTables *rt = (ReedSolomonTables *)
calloc(1, sizeof(ReedSolomonTables));
rt->gfTables = gt;
rt->fcr = first_consecutive_root;
@ -106,7 +110,7 @@ ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
rt->nroots = nroots_in;
rt->ndata = GF_FIELDMAX - rt->nroots;
rt->gpoly = (int32 *)calloc((rt->nroots+1), sizeof(int32));
rt->gpoly = (int32_t *)calloc((rt->nroots+1), sizeof(int32_t));
/* Create the RS code generator polynomial */
@ -115,42 +119,31 @@ ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
for(i=0, root=first_consecutive_root*prim_elem; i<rt->nroots; i++, root+=prim_elem)
{ rt->gpoly[i+1] = 1;
/* Multiply gpoly by alpha**(root+x) */
/* Multiply gpoly by alpha**(root+x) */
for(j=i; j>0; j--)
{
if(rt->gpoly[j] != 0)
rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
else
rt->gpoly[j] = rt->gpoly[j-1];
}
for(j=i; j>0; j--)
{
if(rt->gpoly[j] != 0)
rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
else
rt->gpoly[j] = rt->gpoly[j-1];
}
rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
}
/* Store the polynomials index for faster encoding */
for(i=0; i<=rt->nroots; i++)
rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
#if 0
/* for the precalculated unrolled loops only */
for(i=gt->nroots-1; i>0; i--)
PrintCLI(
" par_idx[((++spk)&%d)] ^= enc_alpha_to[feedback + %3d];\n",
nroots-1,gt->gpoly[i]);
PrintCLI(" par_idx[sp] = enc_alpha_to[feedback + %3d];\n",
gt->gpoly[0]);
#endif
rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
return rt;
}
void FreeReedSolomonTables(ReedSolomonTables *rt)
{
if(rt->gpoly) free(rt->gpoly);
if(rt->gpoly)
free(rt->gpoly);
free(rt);
free(rt);
}

76
mednafen/cdrom/galois.h Normal file
View File

@ -0,0 +1,76 @@
#ifndef _GALOIS_H
#define _GALOIS_H
#include <stdint.h>
#include <retro_inline.h>
#ifdef __cplusplus
extern "C" {
#endif
/***
*** galois.c
***
* This is currently the hardcoded GF(2**8).
* int32_t gives abundant space for the GF.
* Squeezing it down to uint8 won't probably gain much,
* so we implement this defensively here.
*
* Note that some performance critical stuff needs to
* be #included from galois-inlines.h
*/
/* Galois field parameters for 8bit symbol Reed-Solomon code */
#define GF_SYMBOLSIZE 8
#define GF_FIELDSIZE (1<<GF_SYMBOLSIZE)
#define GF_FIELDMAX (GF_FIELDSIZE-1)
#define GF_ALPHA0 GF_FIELDMAX
/* Lookup tables for Galois field arithmetic */
typedef struct _GaloisTables
{ int32_t gfGenerator; /* GF generator polynomial */
int32_t *indexOf; /* log */
int32_t *alphaTo; /* inverse log */
int32_t *encAlphaTo; /* inverse log optimized for encoder */
} GaloisTables;
/* Lookup and working tables for the ReedSolomon codecs */
typedef struct _ReedSolomonTables
{
GaloisTables *gfTables;/* from above */
int32_t *gpoly; /* RS code generator polynomial */
int32_t fcr; /* first consecutive root of RS generator polynomial */
int32_t primElem; /* primitive field element */
int32_t nroots; /* degree of RS generator polynomial */
int32_t ndata; /* data bytes per ecc block */
} ReedSolomonTables;
/*
* The following routine is performance critical.
*/
static INLINE int mod_fieldmax(int x)
{
while (x >= GF_FIELDMAX)
{
x -= GF_FIELDMAX;
x = (x >> GF_SYMBOLSIZE) + (x & GF_FIELDMAX);
}
return x;
}
GaloisTables* CreateGaloisTables(int32_t a);
void FreeGaloisTables(GaloisTables *a);
ReedSolomonTables *CreateReedSolomonTables(GaloisTables *a, int32_t b, int32_t c, int d);
void FreeReedSolomonTables(ReedSolomonTables *a);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -22,11 +22,11 @@
* or direct your browser at http://www.gnu.org.
*/
#include "dvdisaster.h"
#include "l-ec.h"
#include <stdlib.h>
#include <string.h>
#include "galois-inlines.h"
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#include <retro_miscellaneous.h>
/***
*** Mapping between cd frame and parity vectors
@ -228,7 +228,8 @@ int CountC2Errors(unsigned char *frame)
int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
int *erasure_list, int erasure_count)
{ GaloisTables *gt = rt->gfTables;
{
GaloisTables *gt = rt->gfTables;
int syndrome[NROOTS];
int lambda[NROOTS+1];
int omega[NROOTS+1];
@ -243,18 +244,18 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
int corrected = 0;
int i,j,k;
int r,el;
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
for(i=0; i<NROOTS; i++)
syndrome[i] = data[0];
syndrome[i] = data[0];
for(j=1; j<shortened_size; j++)
for(i=0; i<NROOTS; i++)
if(syndrome[i] == 0)
syndrome[i] = data[j];
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
for(i=0; i<NROOTS; i++)
if(syndrome[i] == 0)
syndrome[i] = data[j];
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
/*** Convert syndrome to index form, check for nonzero condition. */
@ -267,7 +268,7 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
/*** If the syndrome is zero, everything is fine. */
if(!syn_error)
return 0;
return 0;
/*** Initialize lambda to be the erasure locator polynomial */
@ -278,7 +279,7 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
erasure_list[1] += padding;
if(erasure_count > 2) /* sanity check */
erasure_count = 0;
erasure_count = 0;
if(erasure_count > 0)
{ lambda[1] = gt->alphaTo[mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[0]))];
@ -287,17 +288,17 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
{ int u = mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[i]));
for(j=i+1; j>0; j--)
{ int tmp = gt->indexOf[lambda[j-1]];
{ int tmp = gt->indexOf[lambda[j-1]];
if(tmp != GF_ALPHA0)
lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
}
lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
}
}
}
for(i=0; i<NROOTS+1; i++)
b[i] = gt->indexOf[lambda[i]];
b[i] = gt->indexOf[lambda[i]];
/*** Berlekamp-Massey algorithm to determine error+erasure locator polynomial */
r = erasure_count; /* r is the step number */
@ -309,42 +310,42 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
{ int discr_r = 0;
for(i=0; i<r; i++)
if((lambda[i] != 0) && (syndrome[r-i-1] != GF_ALPHA0))
discr_r ^= gt->alphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
if((lambda[i] != 0) && (syndrome[r-i-1] != GF_ALPHA0))
discr_r ^= gt->alphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
discr_r = gt->indexOf[discr_r];
if(discr_r == GF_ALPHA0)
{ /* B(x) = x*B(x) */
memmove(b+1, b, NROOTS*sizeof(b[0]));
b[0] = GF_ALPHA0;
memmove(b+1, b, NROOTS*sizeof(b[0]));
b[0] = GF_ALPHA0;
}
else
{ int t[NROOTS+1];
/* T(x) = lambda(x) - discr_r*x*b(x) */
t[0] = lambda[0];
for(i=0; i<NROOTS; i++)
{ if(b[i] != GF_ALPHA0)
t[i+1] = lambda[i+1] ^ gt->alphaTo[mod_fieldmax(discr_r + b[i])];
else t[i+1] = lambda[i+1];
}
/* T(x) = lambda(x) - discr_r*x*b(x) */
t[0] = lambda[0];
for(i=0; i<NROOTS; i++)
{ if(b[i] != GF_ALPHA0)
t[i+1] = lambda[i+1] ^ gt->alphaTo[mod_fieldmax(discr_r + b[i])];
else t[i+1] = lambda[i+1];
}
if(2*el <= r+erasure_count-1)
{ el = r + erasure_count - el;
if(2*el <= r+erasure_count-1)
{ el = r + erasure_count - el;
/* B(x) <-- inv(discr_r) * lambda(x) */
for(i=0; i<=NROOTS; i++)
b[i] = (lambda[i] == 0) ? GF_ALPHA0
: mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
}
else
{ /* 2 lines below: B(x) <-- x*B(x) */
memmove(b+1, b, NROOTS*sizeof(b[0]));
b[0] = GF_ALPHA0;
}
/* B(x) <-- inv(discr_r) * lambda(x) */
for(i=0; i<=NROOTS; i++)
b[i] = (lambda[i] == 0) ? GF_ALPHA0
: mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
}
else
{ /* 2 lines below: B(x) <-- x*B(x) */
memmove(b+1, b, NROOTS*sizeof(b[0]));
b[0] = GF_ALPHA0;
}
memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
}
}
@ -354,7 +355,7 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
for(i=0; i<NROOTS+1; i++)
{ lambda[i] = gt->indexOf[lambda[i]];
if(lambda[i] != GF_ALPHA0)
deg_lambda = i;
deg_lambda = i;
}
/*** Find roots of the error+erasure locator polynomial by Chien search */
@ -367,9 +368,9 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
for(j=deg_lambda; j>0; j--)
{ if(reg[j] != GF_ALPHA0)
{ reg[j] = mod_fieldmax(reg[j] + j);
q ^= gt->alphaTo[reg[j]];
}
{ reg[j] = mod_fieldmax(reg[j] + j);
q ^= gt->alphaTo[reg[j]];
}
}
if(q != 0) continue; /* Not a root */
@ -401,7 +402,7 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
for(j=i; j>=0; j--)
{ if((syndrome[i - j] != GF_ALPHA0) && (lambda[j] != GF_ALPHA0))
tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
}
omega[i] = gt->indexOf[tmp];
@ -420,59 +421,54 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
for(i=deg_omega; i>=0; i--)
{ if(omega[i] != GF_ALPHA0)
num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
}
num2 = gt->alphaTo[mod_fieldmax(root[j] * (LEC_FIRST_ROOT - 1) + GF_FIELDMAX)];
den = 0;
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
for(i=MIN(deg_lambda, NROOTS-1) & ~1; i>=0; i-=2)
{ if(lambda[i+1] != GF_ALPHA0)
den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
}
/* Apply error to data */
if(num1 != 0 && location >= padding)
{
corrected++;
data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
+ GF_FIELDMAX - gt->indexOf[den])];
corrected++;
data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
+ GF_FIELDMAX - gt->indexOf[den])];
/* If no erasures were given, at most one error was corrected.
Return its position in erasure_list[0]. */
/* If no erasures were given, at most one error was corrected.
Return its position in erasure_list[0]. */
if(!erasure_count)
erasure_list[0] = location-padding;
if(!erasure_count)
erasure_list[0] = location-padding;
}
#if 1
else return -3;
#endif
else
return -3;
}
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
for(i=0; i<NROOTS; i++)
syndrome[i] = data[0];
syndrome[i] = data[0];
for(j=1; j<shortened_size; j++)
for(i=0; i<NROOTS; i++)
{ if(syndrome[i] == 0)
syndrome[i] = data[j];
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
}
for(i=0; i<NROOTS; i++)
{ if(syndrome[i] == 0)
syndrome[i] = data[j];
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
}
/*** Convert syndrome to index form, check for nonzero condition. */
#if 1
for(i=0; i<NROOTS; i++)
if(syndrome[i])
return -2;
#endif
if(syndrome[i])
return -2;
return corrected;
}

45
mednafen/cdrom/l-ec.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef _L_EC_H
#define _L_EC_H
#include <stdint.h>
#include "galois.h"
#ifdef __cplusplus
extern "C" {
#endif
#define N_P_VECTORS 86 /* 43 16bit p vectors */
#define P_VECTOR_SIZE 26 /* using RS(26,24) ECC */
#define N_Q_VECTORS 52 /* 26 16bit q vectors */
#define Q_VECTOR_SIZE 45 /* using RS(45,43) ECC */
#define P_PADDING 229 /* padding values for */
#define Q_PADDING 210 /* shortened RS code */
int PToByteIndex(int, int);
int QToByteIndex(int, int);
void ByteIndexToP(int, int*, int*);
void ByteIndexToQ(int, int*, int*);
void GetPVector(unsigned char*, unsigned char*, int);
void SetPVector(unsigned char*, unsigned char*, int);
void FillPVector(unsigned char*, unsigned char, int);
void AndPVector(unsigned char*, unsigned char, int);
void OrPVector(unsigned char*, unsigned char, int);
void GetQVector(unsigned char*, unsigned char*, int);
void SetQVector(unsigned char*, unsigned char*, int);
void FillQVector(unsigned char*, unsigned char, int);
void AndQVector(unsigned char*, unsigned char, int);
void OrQVector(unsigned char*, unsigned char, int);
int DecodePQ(ReedSolomonTables*, unsigned char*, int, int*, int);
int CountC2Errors(unsigned char*);
#ifdef __cplusplus
}
#endif
#endif

555
mednafen/cdrom/lec.c Normal file
View File

@ -0,0 +1,555 @@
/* cdrdao - write audio CD-Rs in disc-at-once mode
*
* Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <assert.h>
#include <sys/types.h>
#include <stdint.h>
#include "lec.h"
#define GF8_PRIM_POLY 0x11d /* x^8 + x^4 + x^3 + x^2 + 1 */
#define EDC_POLY 0x8001801b /* (x^16 + x^15 + x^2 + 1) (x^16 + x^2 + x + 1) */
#define LEC_HEADER_OFFSET 12
#define LEC_DATA_OFFSET 16
#define LEC_MODE1_DATA_LEN 2048
#define LEC_MODE1_EDC_OFFSET 2064
#define LEC_MODE1_INTERMEDIATE_OFFSET 2068
#define LEC_MODE1_P_PARITY_OFFSET 2076
#define LEC_MODE1_Q_PARITY_OFFSET 2248
#define LEC_MODE2_FORM1_DATA_LEN (2048+8)
#define LEC_MODE2_FORM1_EDC_OFFSET 2072
#define LEC_MODE2_FORM2_DATA_LEN (2324+8)
#define LEC_MODE2_FORM2_EDC_OFFSET 2348
static uint8_t GF8_LOG[256];
static uint8_t GF8_ILOG[256];
uint16_t cf8_table[43][256];
uint32_t crc_table[256];
uint8_t scramble_table[2340];
/* Addition in the GF(8) domain: just the XOR of the values.
*/
#define gf8_add(a, b) (a) ^ (b)
/* Division in the GF(8) domain: Like multiplication but logarithms a
* subtracted.
*/
static uint8_t gf8_div(uint8_t a, uint8_t b)
{
int16_t sum;
assert(b != 0);
if (a == 0)
return 0;
sum = GF8_LOG[a] - GF8_LOG[b];
if (sum < 0)
sum += 255;
return GF8_ILOG[sum];
}
/* Reverses the bits in 'd'. 'bits' defines the bit width of 'd'.
*/
static uint32_t mirror_bits(uint32_t d, int bits)
{
int i;
uint32_t r = 0;
for (i = 0; i < bits; i++)
{
r <<= 1;
if ((d & 0x1) != 0)
r |= 0x1;
d >>= 1;
}
return r;
}
/* Calculates the CRC of given data with given lengths based on the
* table lookup algorithm.
*/
static uint32_t calc_edc(uint8_t *data, int len)
{
uint32_t crc = 0;
while (len--)
crc = crc_table[(int)(crc ^ *data++) & 0xff] ^ (crc >> 8);
return crc;
}
/* Build the scramble table as defined in the yellow book. The bytes
12 to 2351 of a sector will be XORed with the data of this table.
*/
static void scramble_table_init(void)
{
uint8_t d;
uint16_t i, j;
uint16_t reg = 1;
for (i = 0; i < 2340; i++)
{
d = 0;
for (j = 0; j < 8; j++)
{
d >>= 1;
if ((reg & 0x1) != 0)
d |= 0x80;
reg >>= 1;
if ((reg & 0x1) != ((reg >> 1) & 0x1))
reg |= 0x4000; /* 15-bit register */
}
scramble_table[i] = d;
}
}
/* Build the CRC lookup table for EDC_POLY poly. The CRC is 32 bit wide
* and reversed (i.e. the bit stream is divided by the EDC_POLY with the
* LSB first order).
*/
static void crc_table_init(void)
{
uint32_t i, j;
uint32_t r;
for (i = 0; i < 256; i++)
{
r = mirror_bits(i, 8);
r <<= 24;
for (j = 0; j < 8; j++)
{
r <<= 1;
if ((r & 0x80000000) != 0)
r ^= EDC_POLY;
}
r = mirror_bits(r, 32);
crc_table[i] = r;
}
}
/* Creates the logarithm and inverse logarithm table that is required
* for performing multiplication in the GF(8) domain.
*/
static void gf8_create_log_tables(void)
{
uint8_t log;
uint16_t b;
for (b = 0; b <= 255; b++)
{
GF8_LOG[b] = 0;
GF8_ILOG[b] = 0;
}
b = 1;
for (log = 0; log < 255; log++)
{
GF8_LOG[(uint8_t)b] = log;
GF8_ILOG[log] = (uint8_t)b;
b <<= 1;
if ((b & 0x100) != 0)
b ^= GF8_PRIM_POLY;
}
}
static void cf8_table_init(void)
{
int i, j;
uint16_t c;
uint8_t GF8_COEFFS_HELP[2][45];
uint8_t GF8_Q_COEFFS[2][45];
gf8_create_log_tables();
/* build matrix H:
* 1 1 ... 1 1
* a^44 a^43 ... a^1 a^0
*
*
*/
for (j = 0; j < 45; j++)
{
GF8_COEFFS_HELP[0][j] = 1; /* e0 */
GF8_COEFFS_HELP[1][j] = GF8_ILOG[44-j]; /* e1 */
}
/* resolve equation system for parity byte 0 and 1 */
/* e1' = e1 + e0 */
for (j = 0; j < 45; j++)
GF8_Q_COEFFS[1][j] = gf8_add(GF8_COEFFS_HELP[1][j],
GF8_COEFFS_HELP[0][j]);
/* e1'' = e1' / (a^1 + 1) */
for (j = 0; j < 45; j++)
GF8_Q_COEFFS[1][j] = gf8_div(GF8_Q_COEFFS[1][j], GF8_Q_COEFFS[1][43]);
/* e0' = e0 + e1 / a^1 */
for (j = 0; j < 45; j++)
GF8_Q_COEFFS[0][j] = gf8_add(GF8_COEFFS_HELP[0][j],
gf8_div(GF8_COEFFS_HELP[1][j],
GF8_ILOG[1]));
/* e0'' = e0' / (1 + 1 / a^1) */
for (j = 0; j < 45; j++)
GF8_Q_COEFFS[0][j] = gf8_div(GF8_Q_COEFFS[0][j], GF8_Q_COEFFS[0][44]);
/*
* Compute the products of 0..255 with all of the Q coefficients in
* advance. When building the scalar product between the data vectors
* and the P/Q vectors the individual products can be looked up in
* this table
*
* The P parity coefficients are just a subset of the Q coefficients so
* that we do not need to create a separate table for them.
*/
for (j = 0; j < 43; j++)
{
cf8_table[j][0] = 0;
for (i = 1; i < 256; i++)
{
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[0][j]];
if (c >= 255) c -= 255;
cf8_table[j][i] = GF8_ILOG[c];
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[1][j]];
if (c >= 255) c -= 255;
cf8_table[j][i] |= GF8_ILOG[c]<<8;
}
}
}
void lec_tables_init(void)
{
scramble_table_init();
crc_table_init();
cf8_table_init();
}
/* Calc EDC for a MODE 1 sector
*/
static void calc_mode1_edc(uint8_t *sector)
{
uint32_t crc = calc_edc(sector, LEC_MODE1_DATA_LEN + 16);
sector[LEC_MODE1_EDC_OFFSET] = crc & 0xffL;
sector[LEC_MODE1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
sector[LEC_MODE1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
sector[LEC_MODE1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
}
/* Calc EDC for a XA form 1 sector
*/
static void calc_mode2_form1_edc(uint8_t *sector)
{
uint32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
LEC_MODE2_FORM1_DATA_LEN);
sector[LEC_MODE2_FORM1_EDC_OFFSET] = crc & 0xffL;
sector[LEC_MODE2_FORM1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
sector[LEC_MODE2_FORM1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
sector[LEC_MODE2_FORM1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
}
/* Calc EDC for a XA form 2 sector
*/
static void calc_mode2_form2_edc(uint8_t *sector)
{
uint32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
LEC_MODE2_FORM2_DATA_LEN);
sector[LEC_MODE2_FORM2_EDC_OFFSET] = crc & 0xffL;
sector[LEC_MODE2_FORM2_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
sector[LEC_MODE2_FORM2_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
sector[LEC_MODE2_FORM2_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
}
/* Writes the sync pattern to the given sector.
*/
static void set_sync_pattern(uint8_t *sector)
{
sector[0] = 0;
sector[1] = sector[2] = sector[3] = sector[4] = sector[5] =
sector[6] = sector[7] = sector[8] = sector[9] = sector[10] = 0xff;
sector[11] = 0;
}
static uint8_t bin2bcd(uint8_t b)
{
return (((b/10) << 4) & 0xf0) | ((b%10) & 0x0f);
}
/* Builds the sector header.
*/
static void set_sector_header(uint8_t mode, uint32_t adr, uint8_t *sector)
{
sector[LEC_HEADER_OFFSET] = bin2bcd(adr / (60*75));
sector[LEC_HEADER_OFFSET + 1] = bin2bcd((adr / 75) % 60);
sector[LEC_HEADER_OFFSET + 2] = bin2bcd(adr % 75);
sector[LEC_HEADER_OFFSET + 3] = mode;
}
/* Calculate the P parities for the sector.
* The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
*/
static void calc_P_parity(uint8_t *sector)
{
int i, j;
uint16_t p01_msb, p01_lsb;
uint8_t *p_lsb_start;
uint8_t *p_lsb;
uint8_t *p0, *p1;
uint8_t d0,d1;
p_lsb_start = sector + LEC_HEADER_OFFSET;
p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
for (i = 0; i <= 42; i++)
{
p_lsb = p_lsb_start;
p01_lsb = p01_msb = 0;
for (j = 19; j <= 42; j++)
{
d0 = *p_lsb;
d1 = *(p_lsb+1);
p01_lsb ^= cf8_table[j][d0];
p01_msb ^= cf8_table[j][d1];
p_lsb += 2 * 43;
}
*p0 = p01_lsb;
*(p0 + 1) = p01_msb;
*p1 = p01_lsb>>8;
*(p1 + 1) = p01_msb>>8;
p0 += 2;
p1 += 2;
p_lsb_start += 2;
}
}
/* Calculate the Q parities for the sector.
* The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
*/
static void calc_Q_parity(uint8_t *sector)
{
int i, j;
uint16_t q01_lsb, q01_msb;
uint8_t *q_lsb_start;
uint8_t *q_lsb;
uint8_t *q0, *q1, *q_start;
uint8_t d0,d1;
q_lsb_start = sector + LEC_HEADER_OFFSET;
q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
for (i = 0; i <= 25; i++)
{
q_lsb = q_lsb_start;
q01_lsb = q01_msb = 0;
for (j = 0; j <= 42; j++)
{
d0 = *q_lsb;
d1 = *(q_lsb+1);
q01_lsb ^= cf8_table[j][d0];
q01_msb ^= cf8_table[j][d1];
q_lsb += 2 * 44;
if (q_lsb >= q_start)
q_lsb -= 2 * 1118;
}
*q0 = q01_lsb;
*(q0 + 1) = q01_msb;
*q1 = q01_lsb>>8;
*(q1 + 1) = q01_msb>>8;
q0 += 2;
q1 += 2;
q_lsb_start += 2 * 43;
}
}
/* Encodes a MODE 0 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide
*/
void lec_encode_mode0_sector(uint32_t adr, uint8_t *sector)
{
uint16_t i;
set_sync_pattern(sector);
set_sector_header(0, adr, sector);
sector += 16;
for (i = 0; i < 2336; i++)
*sector++ = 0;
}
/* Encodes a MODE 1 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
* offset 16
*/
void lec_encode_mode1_sector(uint32_t adr, uint8_t *sector)
{
set_sync_pattern(sector);
set_sector_header(1, adr, sector);
calc_mode1_edc(sector);
/* clear the intermediate field */
sector[LEC_MODE1_INTERMEDIATE_OFFSET] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 1] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 2] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 3] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 4] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 5] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 6] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 7] = 0;
calc_P_parity(sector);
calc_Q_parity(sector);
}
/* Encodes a MODE 2 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
* offset 16
*/
void lec_encode_mode2_sector(uint32_t adr, uint8_t *sector)
{
set_sync_pattern(sector);
set_sector_header(2, adr, sector);
}
/* Encodes a XA form 1 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
* offset 16
*/
void lec_encode_mode2_form1_sector(uint32_t adr, uint8_t *sector)
{
set_sync_pattern(sector);
calc_mode2_form1_edc(sector);
/* P/Q partiy must not contain the sector header so clear it */
sector[LEC_HEADER_OFFSET] =
sector[LEC_HEADER_OFFSET + 1] =
sector[LEC_HEADER_OFFSET + 2] =
sector[LEC_HEADER_OFFSET + 3] = 0;
calc_P_parity(sector);
calc_Q_parity(sector);
/* finally add the sector header */
set_sector_header(2, adr, sector);
}
/* Encodes a XA form 2 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
* offset 16
*/
void lec_encode_mode2_form2_sector(uint32_t adr, uint8_t *sector)
{
set_sync_pattern(sector);
calc_mode2_form2_edc(sector);
set_sector_header(2, adr, sector);
}
/* Scrambles and byte swaps an encoded sector.
* 'sector' must be 2352 byte wide.
*/
void lec_scramble(uint8_t *sector)
{
uint16_t i;
uint8_t *p = sector;
uint8_t tmp;
const uint8_t *stable = scramble_table;
for (i = 0; i < 6; i++)
{
/* just swap bytes of sector sync */
tmp = *p;
*p = *(p + 1);
p++;
*p++ = tmp;
}
for (;i < (2352 / 2); i++)
{
/* scramble and swap bytes */
tmp = *p ^ *stable++;
*p = *(p + 1) ^ *stable++;
p++;
*p++ = tmp;
}
}

View File

@ -1,691 +0,0 @@
/* cdrdao - write audio CD-Rs in disc-at-once mode
*
* Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <sys/types.h>
#include "lec.h"
#define GF8_PRIM_POLY 0x11d /* x^8 + x^4 + x^3 + x^2 + 1 */
#define EDC_POLY 0x8001801b /* (x^16 + x^15 + x^2 + 1) (x^16 + x^2 + x + 1) */
#define LEC_HEADER_OFFSET 12
#define LEC_DATA_OFFSET 16
#define LEC_MODE1_DATA_LEN 2048
#define LEC_MODE1_EDC_OFFSET 2064
#define LEC_MODE1_INTERMEDIATE_OFFSET 2068
#define LEC_MODE1_P_PARITY_OFFSET 2076
#define LEC_MODE1_Q_PARITY_OFFSET 2248
#define LEC_MODE2_FORM1_DATA_LEN (2048+8)
#define LEC_MODE2_FORM1_EDC_OFFSET 2072
#define LEC_MODE2_FORM2_DATA_LEN (2324+8)
#define LEC_MODE2_FORM2_EDC_OFFSET 2348
typedef u_int8_t gf8_t;
static u_int8_t GF8_LOG[256];
static gf8_t GF8_ILOG[256];
static const class Gf8_Q_Coeffs_Results_01 {
private:
u_int16_t table[43][256];
public:
Gf8_Q_Coeffs_Results_01();
~Gf8_Q_Coeffs_Results_01() {}
const u_int16_t *operator[] (int i) const { return &table[i][0]; }
operator const u_int16_t *() const { return &table[0][0]; }
} CF8_Q_COEFFS_RESULTS_01;
static const class CrcTable {
private:
u_int32_t table[256];
public:
CrcTable();
~CrcTable() {}
u_int32_t operator[](int i) const { return table[i]; }
operator const u_int32_t *() const { return table; }
} CRCTABLE;
static const class ScrambleTable {
private:
u_int8_t table[2340];
public:
ScrambleTable();
~ScrambleTable() {}
u_int8_t operator[](int i) const { return table[i]; }
operator const u_int8_t *() const { return table; }
} SCRAMBLE_TABLE;
/* Creates the logarithm and inverse logarithm table that is required
* for performing multiplication in the GF(8) domain.
*/
static void gf8_create_log_tables()
{
u_int8_t log;
u_int16_t b;
for (b = 0; b <= 255; b++) {
GF8_LOG[b] = 0;
GF8_ILOG[b] = 0;
}
b = 1;
for (log = 0; log < 255; log++) {
GF8_LOG[(u_int8_t)b] = log;
GF8_ILOG[log] = (u_int8_t)b;
b <<= 1;
if ((b & 0x100) != 0)
b ^= GF8_PRIM_POLY;
}
}
/* Addition in the GF(8) domain: just the XOR of the values.
*/
#define gf8_add(a, b) (a) ^ (b)
/* Multiplication in the GF(8) domain: add the logarithms (modulo 255)
* and return the inverse logarithm. Not used!
*/
#if 0
static gf8_t gf8_mult(gf8_t a, gf8_t b)
{
int16_t sum;
if (a == 0 || b == 0)
return 0;
sum = GF8_LOG[a] + GF8_LOG[b];
if (sum >= 255)
sum -= 255;
return GF8_ILOG[sum];
}
#endif
/* Division in the GF(8) domain: Like multiplication but logarithms a
* subtracted.
*/
static gf8_t gf8_div(gf8_t a, gf8_t b)
{
int16_t sum;
assert(b != 0);
if (a == 0)
return 0;
sum = GF8_LOG[a] - GF8_LOG[b];
if (sum < 0)
sum += 255;
return GF8_ILOG[sum];
}
Gf8_Q_Coeffs_Results_01::Gf8_Q_Coeffs_Results_01()
{
int i, j;
u_int16_t c;
gf8_t GF8_COEFFS_HELP[2][45];
u_int8_t GF8_Q_COEFFS[2][45];
gf8_create_log_tables();
/* build matrix H:
* 1 1 ... 1 1
* a^44 a^43 ... a^1 a^0
*
*
*/
for (j = 0; j < 45; j++) {
GF8_COEFFS_HELP[0][j] = 1; /* e0 */
GF8_COEFFS_HELP[1][j] = GF8_ILOG[44-j]; /* e1 */
}
/* resolve equation system for parity byte 0 and 1 */
/* e1' = e1 + e0 */
for (j = 0; j < 45; j++) {
GF8_Q_COEFFS[1][j] = gf8_add(GF8_COEFFS_HELP[1][j],
GF8_COEFFS_HELP[0][j]);
}
/* e1'' = e1' / (a^1 + 1) */
for (j = 0; j < 45; j++) {
GF8_Q_COEFFS[1][j] = gf8_div(GF8_Q_COEFFS[1][j], GF8_Q_COEFFS[1][43]);
}
/* e0' = e0 + e1 / a^1 */
for (j = 0; j < 45; j++) {
GF8_Q_COEFFS[0][j] = gf8_add(GF8_COEFFS_HELP[0][j],
gf8_div(GF8_COEFFS_HELP[1][j],
GF8_ILOG[1]));
}
/* e0'' = e0' / (1 + 1 / a^1) */
for (j = 0; j < 45; j++) {
GF8_Q_COEFFS[0][j] = gf8_div(GF8_Q_COEFFS[0][j], GF8_Q_COEFFS[0][44]);
}
/*
* Compute the products of 0..255 with all of the Q coefficients in
* advance. When building the scalar product between the data vectors
* and the P/Q vectors the individual products can be looked up in
* this table
*
* The P parity coefficients are just a subset of the Q coefficients so
* that we do not need to create a separate table for them.
*/
for (j = 0; j < 43; j++) {
table[j][0] = 0;
for (i = 1; i < 256; i++) {
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[0][j]];
if (c >= 255) c -= 255;
table[j][i] = GF8_ILOG[c];
c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[1][j]];
if (c >= 255) c -= 255;
table[j][i] |= GF8_ILOG[c]<<8;
}
}
}
/* Reverses the bits in 'd'. 'bits' defines the bit width of 'd'.
*/
static u_int32_t mirror_bits(u_int32_t d, int bits)
{
int i;
u_int32_t r = 0;
for (i = 0; i < bits; i++) {
r <<= 1;
if ((d & 0x1) != 0)
r |= 0x1;
d >>= 1;
}
return r;
}
/* Build the CRC lookup table for EDC_POLY poly. The CRC is 32 bit wide
* and reversed (i.e. the bit stream is divided by the EDC_POLY with the
* LSB first order).
*/
CrcTable::CrcTable ()
{
u_int32_t i, j;
u_int32_t r;
for (i = 0; i < 256; i++) {
r = mirror_bits(i, 8);
r <<= 24;
for (j = 0; j < 8; j++) {
if ((r & 0x80000000) != 0) {
r <<= 1;
r ^= EDC_POLY;
}
else {
r <<= 1;
}
}
r = mirror_bits(r, 32);
table[i] = r;
}
}
/* Calculates the CRC of given data with given lengths based on the
* table lookup algorithm.
*/
static u_int32_t calc_edc(u_int8_t *data, int len)
{
u_int32_t crc = 0;
while (len--) {
crc = CRCTABLE[(int)(crc ^ *data++) & 0xff] ^ (crc >> 8);
}
return crc;
}
/* Build the scramble table as defined in the yellow book. The bytes
12 to 2351 of a sector will be XORed with the data of this table.
*/
ScrambleTable::ScrambleTable()
{
u_int16_t i, j;
u_int16_t reg = 1;
u_int8_t d;
for (i = 0; i < 2340; i++) {
d = 0;
for (j = 0; j < 8; j++) {
d >>= 1;
if ((reg & 0x1) != 0)
d |= 0x80;
if ((reg & 0x1) != ((reg >> 1) & 0x1)) {
reg >>= 1;
reg |= 0x4000; /* 15-bit register */
}
else {
reg >>= 1;
}
}
table[i] = d;
}
}
/* Calc EDC for a MODE 1 sector
*/
static void calc_mode1_edc(u_int8_t *sector)
{
u_int32_t crc = calc_edc(sector, LEC_MODE1_DATA_LEN + 16);
sector[LEC_MODE1_EDC_OFFSET] = crc & 0xffL;
sector[LEC_MODE1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
sector[LEC_MODE1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
sector[LEC_MODE1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
}
/* Calc EDC for a XA form 1 sector
*/
static void calc_mode2_form1_edc(u_int8_t *sector)
{
u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
LEC_MODE2_FORM1_DATA_LEN);
sector[LEC_MODE2_FORM1_EDC_OFFSET] = crc & 0xffL;
sector[LEC_MODE2_FORM1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
sector[LEC_MODE2_FORM1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
sector[LEC_MODE2_FORM1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
}
/* Calc EDC for a XA form 2 sector
*/
static void calc_mode2_form2_edc(u_int8_t *sector)
{
u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
LEC_MODE2_FORM2_DATA_LEN);
sector[LEC_MODE2_FORM2_EDC_OFFSET] = crc & 0xffL;
sector[LEC_MODE2_FORM2_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
sector[LEC_MODE2_FORM2_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
sector[LEC_MODE2_FORM2_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
}
/* Writes the sync pattern to the given sector.
*/
static void set_sync_pattern(u_int8_t *sector)
{
sector[0] = 0;
sector[1] = sector[2] = sector[3] = sector[4] = sector[5] =
sector[6] = sector[7] = sector[8] = sector[9] = sector[10] = 0xff;
sector[11] = 0;
}
static u_int8_t bin2bcd(u_int8_t b)
{
return (((b/10) << 4) & 0xf0) | ((b%10) & 0x0f);
}
/* Builds the sector header.
*/
static void set_sector_header(u_int8_t mode, u_int32_t adr, u_int8_t *sector)
{
sector[LEC_HEADER_OFFSET] = bin2bcd(adr / (60*75));
sector[LEC_HEADER_OFFSET + 1] = bin2bcd((adr / 75) % 60);
sector[LEC_HEADER_OFFSET + 2] = bin2bcd(adr % 75);
sector[LEC_HEADER_OFFSET + 3] = mode;
}
/* Calculate the P parities for the sector.
* The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
*/
static void calc_P_parity(u_int8_t *sector)
{
int i, j;
u_int16_t p01_msb, p01_lsb;
u_int8_t *p_lsb_start;
u_int8_t *p_lsb;
u_int8_t *p0, *p1;
u_int8_t d0,d1;
p_lsb_start = sector + LEC_HEADER_OFFSET;
p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
for (i = 0; i <= 42; i++) {
p_lsb = p_lsb_start;
p01_lsb = p01_msb = 0;
for (j = 19; j <= 42; j++) {
d0 = *p_lsb;
d1 = *(p_lsb+1);
p01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
p01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
p_lsb += 2 * 43;
}
*p0 = p01_lsb;
*(p0 + 1) = p01_msb;
*p1 = p01_lsb>>8;
*(p1 + 1) = p01_msb>>8;
p0 += 2;
p1 += 2;
p_lsb_start += 2;
}
}
/* Calculate the Q parities for the sector.
* The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
*/
static void calc_Q_parity(u_int8_t *sector)
{
int i, j;
u_int16_t q01_lsb, q01_msb;
u_int8_t *q_lsb_start;
u_int8_t *q_lsb;
u_int8_t *q0, *q1, *q_start;
u_int8_t d0,d1;
q_lsb_start = sector + LEC_HEADER_OFFSET;
q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
for (i = 0; i <= 25; i++) {
q_lsb = q_lsb_start;
q01_lsb = q01_msb = 0;
for (j = 0; j <= 42; j++) {
d0 = *q_lsb;
d1 = *(q_lsb+1);
q01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0];
q01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1];
q_lsb += 2 * 44;
if (q_lsb >= q_start) {
q_lsb -= 2 * 1118;
}
}
*q0 = q01_lsb;
*(q0 + 1) = q01_msb;
*q1 = q01_lsb>>8;
*(q1 + 1) = q01_msb>>8;
q0 += 2;
q1 += 2;
q_lsb_start += 2 * 43;
}
}
/* Encodes a MODE 0 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide
*/
void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector)
{
u_int16_t i;
set_sync_pattern(sector);
set_sector_header(0, adr, sector);
sector += 16;
for (i = 0; i < 2336; i++)
*sector++ = 0;
}
/* Encodes a MODE 1 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
* offset 16
*/
void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector)
{
set_sync_pattern(sector);
set_sector_header(1, adr, sector);
calc_mode1_edc(sector);
/* clear the intermediate field */
sector[LEC_MODE1_INTERMEDIATE_OFFSET] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 1] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 2] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 3] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 4] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 5] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 6] =
sector[LEC_MODE1_INTERMEDIATE_OFFSET + 7] = 0;
calc_P_parity(sector);
calc_Q_parity(sector);
}
/* Encodes a MODE 2 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
* offset 16
*/
void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector)
{
set_sync_pattern(sector);
set_sector_header(2, adr, sector);
}
/* Encodes a XA form 1 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
* offset 16
*/
void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector)
{
set_sync_pattern(sector);
calc_mode2_form1_edc(sector);
/* P/Q partiy must not contain the sector header so clear it */
sector[LEC_HEADER_OFFSET] =
sector[LEC_HEADER_OFFSET + 1] =
sector[LEC_HEADER_OFFSET + 2] =
sector[LEC_HEADER_OFFSET + 3] = 0;
calc_P_parity(sector);
calc_Q_parity(sector);
/* finally add the sector header */
set_sector_header(2, adr, sector);
}
/* Encodes a XA form 2 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
* offset 16
*/
void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector)
{
set_sync_pattern(sector);
calc_mode2_form2_edc(sector);
set_sector_header(2, adr, sector);
}
/* Scrambles and byte swaps an encoded sector.
* 'sector' must be 2352 byte wide.
*/
void lec_scramble(u_int8_t *sector)
{
u_int16_t i;
const u_int8_t *stable = SCRAMBLE_TABLE;
u_int8_t *p = sector;
u_int8_t tmp;
for (i = 0; i < 6; i++) {
/* just swap bytes of sector sync */
tmp = *p;
*p = *(p + 1);
p++;
*p++ = tmp;
}
for (;i < (2352 / 2); i++) {
/* scramble and swap bytes */
tmp = *p ^ *stable++;
*p = *(p + 1) ^ *stable++;
p++;
*p++ = tmp;
}
}
#if 0
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char **argv)
{
char *infile;
char *outfile;
int fd_in, fd_out;
u_int8_t buffer1[2352];
u_int8_t buffer2[2352];
u_int32_t lba;
int i;
#if 0
for (i = 0; i < 2048; i++)
buffer1[i + 16] = 234;
lba = 150;
for (i = 0; i < 100000; i++) {
lec_encode_mode1_sector(lba, buffer1);
lec_scramble(buffer2);
lba++;
}
#else
if (argc != 3)
return 1;
infile = argv[1];
outfile = argv[2];
if ((fd_in = open(infile, O_RDONLY)) < 0) {
perror("Cannot open input file");
return 1;
}
if ((fd_out = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
perror("Cannot open output file");
return 1;
}
lba = 150;
do {
if (read(fd_in, buffer1, 2352) != 2352)
break;
switch (*(buffer1 + 12 + 3)) {
case 1:
memcpy(buffer2 + 16, buffer1 + 16, 2048);
lec_encode_mode1_sector(lba, buffer2);
break;
case 2:
if ((*(buffer1 + 12 + 4 + 2) & 0x20) != 0) {
/* form 2 sector */
memcpy(buffer2 + 16, buffer1 + 16, 2324 + 8);
lec_encode_mode2_form2_sector(lba, buffer2);
}
else {
/* form 1 sector */
memcpy(buffer2 + 16, buffer1 + 16, 2048 + 8);
lec_encode_mode2_form1_sector(lba, buffer2);
}
break;
}
if (memcmp(buffer1, buffer2, 2352) != 0) {
printf("Verify error at lba %ld\n", lba);
}
lec_scramble(buffer2);
write(fd_out, buffer2, 2352);
lba++;
} while (1);
close(fd_in);
close(fd_out);
#endif
return 0;
}
#endif

View File

@ -20,15 +20,12 @@
#ifndef __LEC_H__
#define __LEC_H__
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdint.h>
#include <boolean.h>
typedef uint32_t u_int32_t;
typedef uint16_t u_int16_t;
typedef uint8_t u_int8_t;
#ifdef __cplusplus
extern "C" {
#endif
#ifndef TRUE
#define TRUE 1
@ -38,39 +35,45 @@ typedef uint8_t u_int8_t;
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide
*/
void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector);
void lec_encode_mode0_sector(uint32_t adr, uint8_t *sector);
/* Encodes a MODE 1 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2048 bytes user data at
* offset 16
*/
void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector);
void lec_encode_mode1_sector(uint32_t adr, uint8_t *sector);
/* Encodes a MODE 2 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2336 bytes user data at
* offset 16
*/
void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector);
void lec_encode_mode2_sector(uint32_t adr, uint8_t *sector);
/* Encodes a XA form 1 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
* offset 16
*/
void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector);
void lec_encode_mode2_form1_sector(uint32_t adr, uint8_t *sector);
/* Encodes a XA form 2 sector.
* 'adr' is the current physical sector address
* 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
* offset 16
*/
void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector);
void lec_encode_mode2_form2_sector(uint32_t adr, uint8_t *sector);
/* Scrambles and byte swaps an encoded sector.
* 'sector' must be 2352 byte wide.
*/
void lec_scramble(u_int8_t *sector);
void lec_scramble(uint8_t *sector);
void lec_tables_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -19,23 +19,28 @@
* or direct your browser at http://www.gnu.org.
*/
#include "dvdisaster.h"
#include <stdint.h>
#include <string.h>
#include "recover-raw.h"
#include "l-ec.h"
#include "edc_crc32.h"
#include "galois.h"
static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
static ReedSolomonTables *rt = NULL;
bool Init_LEC_Correct(void)
{
gt = CreateGaloisTables(0x11d);
rt = CreateReedSolomonTables(gt, 0, 1, 10);
gt = CreateGaloisTables(0x11d);
rt = CreateReedSolomonTables(gt, 0, 1, 10);
return(1);
return(1);
}
void Kill_LEC_Correct(void)
{
FreeGaloisTables(gt);
FreeReedSolomonTables(rt);
FreeGaloisTables(gt);
FreeReedSolomonTables(rt);
}
/***
@ -49,26 +54,24 @@ void Kill_LEC_Correct(void)
int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
{
unsigned int expected_crc, real_crc;
unsigned int crc_base = xa_mode ? 2072 : 2064;
unsigned int expected_crc, real_crc;
unsigned int crc_base = xa_mode ? 2072 : 2064;
expected_crc = cd_frame[crc_base + 0] << 0;
expected_crc |= cd_frame[crc_base + 1] << 8;
expected_crc |= cd_frame[crc_base + 2] << 16;
expected_crc |= cd_frame[crc_base + 3] << 24;
expected_crc = cd_frame[crc_base + 0] << 0;
expected_crc |= cd_frame[crc_base + 1] << 8;
expected_crc |= cd_frame[crc_base + 2] << 16;
expected_crc |= cd_frame[crc_base + 3] << 24;
if(xa_mode)
real_crc = EDCCrc32(cd_frame+16, 2056);
else
real_crc = EDCCrc32(cd_frame, 2064);
if(xa_mode)
real_crc = EDCCrc32(cd_frame+16, 2056);
else
real_crc = EDCCrc32(cd_frame, 2064);
if(expected_crc == real_crc)
return(1);
else
{
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
return(0);
}
if(expected_crc == real_crc)
return(1);
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
return(0);
}
/***
@ -101,31 +104,34 @@ static int simple_lec(unsigned char *frame)
/* Perform Q-Parity error correction */
for(q=0; q<N_Q_VECTORS; q++)
{ int err;
{
int err;
/* We have no erasure information for Q vectors */
GetQVector(frame, q_vector, q);
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
GetQVector(frame, q_vector, q);
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
/* See what we've got */
/* See what we've got */
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
{ q_failures++;
FillQVector(byte_state, 1, q);
}
else /* Correctable */
{ if(err == 1 || err == 2) /* Store back corrected vector */
{ SetQVector(frame, q_vector, q);
q_corrected++;
}
}
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
{ q_failures++;
FillQVector(byte_state, 1, q);
}
else /* Correctable */
{
if(err == 1 || err == 2) /* Store back corrected vector */
{
SetQVector(frame, q_vector, q);
q_corrected++;
}
}
}
/* Perform P-Parity error correction */
for(p=0; p<N_P_VECTORS; p++)
{ int err,i;
{
int err,i;
/* Try error correction without erasure information */
@ -133,41 +139,41 @@ static int simple_lec(unsigned char *frame)
err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
/* If unsuccessful, try again using erasures.
Erasure information is uncertain, so try this last. */
Erasure information is uncertain, so try this last. */
if(err < 0 || err > 2)
{ GetPVector(byte_state, p_state, p);
erasure_count = 0;
{
GetPVector(byte_state, p_state, p);
erasure_count = 0;
for(i=0; i<P_VECTOR_SIZE; i++)
if(p_state[i])
erasures[erasure_count++] = i;
for(i=0; i<P_VECTOR_SIZE; i++)
if(p_state[i])
erasures[erasure_count++] = i;
if(erasure_count > 0 && erasure_count <= 2)
{ GetPVector(frame, p_vector, p);
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
}
if(erasure_count > 0 && erasure_count <= 2)
{
GetPVector(frame, p_vector, p);
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
}
}
/* See what we've got */
if(err < 0) /* Uncorrectable. */
{ p_failures++;
}
p_failures++;
else /* Correctable. */
{ if(err == 1 || err == 2) /* Store back corrected vector */
{ SetPVector(frame, p_vector, p);
p_corrected++;
}
{
if(err == 1 || err == 2) /* Store back corrected vector */
{ SetPVector(frame, p_vector, p);
p_corrected++;
}
}
}
/* Sum up */
if(q_failures || p_failures || q_corrected || p_corrected)
{
return 1;
}
return 1;
return 0;
}
@ -177,27 +183,25 @@ static int simple_lec(unsigned char *frame)
***/
int ValidateRawSector(unsigned char *frame, bool xaMode)
{
int lec_did_sth = FALSE;
{
int lec_did_sth = false;
/* Do simple L-EC.
It seems that drives stop their internal L-EC as soon as the
EDC is okay, so we may see uncorrected errors in the parity bytes.
Since we are also interested in the user data only and doing the
L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
// Silence GCC warning
(void)lec_did_sth;
if(!CheckEDC(frame, xaMode))
{
lec_did_sth = simple_lec(frame);
}
/* Test internal sector checksum again */
/* Do simple L-EC.
It seems that drives stop their internal L-EC as soon as the
EDC is okay, so we may see uncorrected errors in the parity bytes.
Since we are also interested in the user data only and doing the
L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
if(!CheckEDC(frame, xaMode))
lec_did_sth = simple_lec(frame);
/* Test internal sector checksum again */
if(!CheckEDC(frame, xaMode))
{
/* EDC failure in RAW sector */
return FALSE;
}
if(!CheckEDC(frame, xaMode))
return false;
return TRUE;
return true;
}

View File

@ -0,0 +1,26 @@
#ifndef _RECOVER_RAW_H
#define _RECOVER_RAW_H
#include <stdint.h>
#include <boolean.h>
#ifdef __cplusplus
extern "C" {
#endif
#define CD_RAW_SECTOR_SIZE 2352
#define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */
int CheckEDC(const unsigned char *a, bool b);
int CheckMSF(unsigned char *a, int b);
int ValidateRawSector(unsigned char *frame, bool xaMode);
bool Init_LEC_Correct(void);
void Kill_LEC_Correct(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -28,8 +28,6 @@ static inline void SCSIDBG(const char *format, ...)
}
//#define SCSIDBG(format, ...) { }
using namespace CDUtility;
static uint32 CD_DATA_TRANSFER_RATE;
static uint32 System_Clock;
static void (*CDIRQCallback)(int);
@ -155,7 +153,7 @@ static cdda_t cdda;
static SimpleFIFO<uint8> din(2048);
static CDUtility::TOC toc;
static TOC toc;
static uint32 read_sec_start;
static uint32 read_sec;
@ -470,7 +468,7 @@ static void DoREADBase(uint32 sa, uint32 sc)
if(SCSILog)
{
int Track = toc.FindTrackByLBA(sa);
int Track = TOC_FindTrackByLBA(&toc, sa);
uint32 Offset = sa - toc.tracks[Track].lba; //Cur_CDIF->GetTrackStartPositionLBA(Track);
SCSILog("SCSI", "Read: start=0x%08x(track=%d, offs=0x%08x), cnt=0x%08x", sa, Track, Offset, sc);
}