ss and pcfx dirs can be whacked (they belong to numa now)

This commit is contained in:
zeromus 2020-06-20 20:11:00 -04:00
parent 602dec0c4c
commit 316aafed40
171 changed files with 0 additions and 145642 deletions

View File

@ -1,16 +0,0 @@
// Place your settings in this file to overwrite default and user settings.
{
"editor.tabSize": 4,
"editor.insertSpaces": false,
"editor.detectIndentation": false,
"files.associations": {
"*.inc": "cpp",
"system_error": "cpp",
"ios": "cpp",
"xiosbase": "cpp",
"iosfwd": "cpp",
"xlocale": "cpp",
"xstring": "cpp",
"queue": "cpp"
}
}

View File

@ -1,10 +0,0 @@
CXXFLAGS := \
-Wall -Werror=int-to-pointer-cast \
-std=c++0x -fomit-frame-pointer -fno-exceptions -fno-rtti \
-DLSB_FIRST
TARGET = pcfx.wbx
SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
include ../common.mak

View File

@ -1,430 +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 "../defs.h"
#include "CDUtility.h"
#include "dvdisaster.h"
#include "lec.h"
#include <assert.h>
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[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(int i = 0; i < 96; i++)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
}
void synth_leadout_sector_lba(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(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
//
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf)
{
uint8 buf[0xC];
uint32 lba_relative;
uint32 ma, sa, fa;
uint32 m, s, f;
if(lba < -150 || lba >= 0)
printf("[BUG] subpw_synth_udapp_lba() lba out of range --- %d\n", lba);
{
int32 lba_tmp = lba + lba_subq_relative_offs;
if(lba_tmp < 0)
lba_relative = 0 - 1 - lba_tmp;
else
lba_relative = lba_tmp - 0;
}
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;
if(toc.disc_type == DISC_TYPE_CD_I && toc.first_track > 1)
control = 0x4;
else if(toc.tracks[toc.first_track].valid)
control = toc.tracks[toc.first_track].control;
else
control = 0x0;
memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4);
buf[1] = U8_to_BCD(toc.first_track);
buf[2] = U8_to_BCD(0x00);
// 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_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf)
{
memset(out_buf, 0, 2352 + 96);
subpw_synth_udapp_lba(toc, lba, lba_subq_relative_offs, 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;
}
}
}
#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,237 +0,0 @@
#ifndef __MDFN_CDROM_CDUTILITY_H
#define __MDFN_CDROM_CDUTILITY_H
namespace CDUtility
{
// 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) MDFN_COLD;
// 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
{
ADR_NOQINFO = 0x00,
ADR_CURPOS = 0x01,
ADR_MCN = 0x02,
ADR_ISRC = 0x03
};
struct TOC_Track
{
uint8 adr;
uint8 control;
uint32 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
{
DISC_TYPE_CDDA_OR_M1 = 0x00,
DISC_TYPE_CD_I = 0x10,
DISC_TYPE_CD_XA = 0x20
};
struct TOC
{
INLINE TOC()
{
Clear();
}
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) const
{
int32 lvt = 0;
for(int32 track = 1; track <= 100; track++)
{
if(!tracks[track].valid)
continue;
if(LBA < tracks[track].lba)
break;
lvt = track;
}
return(lvt);
}
uint8 first_track;
uint8 last_track;
uint8 disc_type;
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
};
//
// 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
// User data area pre-pause(MSF 00:00:00 through 00:01:74), lba -150 through -1
// out_buf must be able to contain 2352+96 bytes.
// "mode" is not used if the area is to be encoded as audio.
// pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.
void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf);
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf);
// out_buf must be able to contain 2352+96 bytes.
// "mode" is not used if the area is to be encoded as audio.
// pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.
void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf);
//
// 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.
//
// Note: mode 2 form 1 L-EC data can't correct errors in the 4-byte sector header(address + mode),
// but the error(s) will still be detected by EDC.
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);
}
#endif

View File

@ -1,114 +0,0 @@
#ifndef __MDFN_SIMPLEFIFO_H
#define __MDFN_SIMPLEFIFO_H
#include <vector>
#include <assert.h>
#include "../math_ops.h"
template<typename T>
class SimpleFIFO
{
public:
// Constructor
SimpleFIFO(uint32 the_size) // Size should be a power of 2!
{
data.resize(round_up_pow2(the_size));
size = the_size;
read_pos = 0;
write_pos = 0;
in_count = 0;
}
// Destructor
INLINE ~SimpleFIFO()
{
}
INLINE void SaveStatePostLoad(void)
{
read_pos %= data.size();
write_pos %= data.size();
in_count %= (data.size() + 1);
}
INLINE uint32 CanRead(void)
{
return(in_count);
}
INLINE uint32 CanWrite(void)
{
return(size - in_count);
}
INLINE T ReadUnit(bool peek = false)
{
T ret;
assert(in_count > 0);
ret = data[read_pos];
if(!peek)
{
read_pos = (read_pos + 1) & (data.size() - 1);
in_count--;
}
return(ret);
}
INLINE uint8 ReadByte(bool peek = false)
{
assert(sizeof(T) == 1);
return(ReadUnit(peek));
}
INLINE void Write(const T *happy_data, uint32 happy_count)
{
assert(CanWrite() >= happy_count);
while(happy_count)
{
data[write_pos] = *happy_data;
write_pos = (write_pos + 1) & (data.size() - 1);
in_count++;
happy_data++;
happy_count--;
}
}
INLINE void WriteUnit(const T& wr_data)
{
Write(&wr_data, 1);
}
INLINE void WriteByte(const T& wr_data)
{
assert(sizeof(T) == 1);
Write(&wr_data, 1);
}
INLINE void Flush(void)
{
read_pos = 0;
write_pos = 0;
in_count = 0;
}
//private:
std::vector<T> data;
uint32 size;
uint32 read_pos; // Read position
uint32 write_pos; // Write position
uint32 in_count; // Number of units in the FIFO
};
#endif

View File

@ -1,131 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* 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 "../defs.h"
#include <string.h>
#include <sys/types.h>
#include "cdromif.h"
//#include "CDAccess.h"
//#include "../general.h"
#include <algorithm>
using namespace CDUtility;
enum
{
// Status/Error messages
CDIF_MSG_DONE = 0, // Read -> emu. args: No args.
CDIF_MSG_INFO, // Read -> emu. args: str_message
CDIF_MSG_FATAL_ERROR, // Read -> emu. args: *TODO ARGS*
//
// Command messages.
//
CDIF_MSG_DIEDIEDIE, // Emu -> read
CDIF_MSG_READ_SECTOR, /* Emu -> read
args[0] = lba
*/
};
typedef struct
{
bool valid;
bool error;
int32 lba;
uint8 data[2352 + 96];
} CDIF_Sector_Buffer;
CDIF::CDIF() : UnrecoverableError(false)
{
}
CDIF::~CDIF()
{
}
bool CDIF::ValidateRawSector(uint8 *buf)
{
int mode = buf[12 + 3];
if(mode != 0x1 && mode != 0x2)
return(false);
if(!edc_lec_check_and_correct(buf, mode == 2))
return(false);
return(true);
}
int CDIF::ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message)
{
int ret = 0;
if(UnrecoverableError)
return(false);
while(sector_count--)
{
uint8 tmpbuf[2352 + 96];
if(!ReadRawSector(tmpbuf, lba))
{
puts("CDIF Raw Read error");
return(FALSE);
}
if(!ValidateRawSector(tmpbuf))
{
/*if(!suppress_uncorrectable_message)
{
MDFN_DispMessage(_("Uncorrectable data at sector %d"), lba);
MDFN_PrintError(_("Uncorrectable data at sector %d"), lba);
}*/
return(false);
}
const int mode = tmpbuf[12 + 3];
if(!ret)
ret = mode;
if(mode == 1)
{
memcpy(buf, &tmpbuf[12 + 4], 2048);
}
else if(mode == 2)
{
memcpy(buf, &tmpbuf[12 + 4 + 8], 2048);
}
else
{
printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba);
return(false);
}
buf += 2048;
lba++;
}
return(ret);
}

View File

@ -1,58 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* 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
*/
#ifndef __MDFN_CDROM_CDROMIF_H
#define __MDFN_CDROM_CDROMIF_H
#include "CDUtility.h"
#include <queue>
typedef CDUtility::TOC CD_TOC;
class CDIF
{
public:
CDIF();
virtual ~CDIF();
static const int32 LBA_Read_Minimum = -150;
static const int32 LBA_Read_Maximum = 449849; // 100 * 75 * 60 - 150 - 1
inline void ReadTOC(CDUtility::TOC *read_target)
{
*read_target = disc_toc;
}
virtual void HintReadSector(int32 lba) = 0;
virtual bool ReadRawSector(uint8 *buf, int32 lba) = 0; // Reads 2352+96 bytes of data into buf.
// Call for mode 1 or mode 2 form 1 only.
bool ValidateRawSector(uint8 *buf);
// Utility/Wrapped functions
// Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
// Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
int ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message = false);
protected:
bool UnrecoverableError;
CDUtility::TOC disc_toc;
};
#endif

View File

@ -1,130 +0,0 @@
/* 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 "dvdisaster.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". */
/* */
/*****************************************************************/
static const 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 EDCCrc32(const unsigned char *data, int len)
{
uint32 crc = 0;
while(len--)
crc = edctable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
return crc;
}

View File

@ -1,171 +0,0 @@
/* 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
*
* 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.
*/
#ifndef DVDISASTER_H
#define DVDISASTER_H
/* "Dare to be gorgeous and unique.
* But don't ever be cryptic or otherwise unfathomable.
* Make it unforgettably great."
*
* From "A Final Note on Style",
* Amiga Intuition Reference Manual, 1986, p. 231
*/
/***
*** I'm too lazy to mess with #include dependencies.
*** Everything #includeable is rolled up herein...
*/
#include "../defs.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/***
*** dvdisaster.c
***/
void PrepareDeadSector(void);
void CreateEcc(void);
void FixEcc(void);
void Verify(void);
uint32 EDCCrc32(const unsigned char*, int);
/***
*** galois.c
***
* This is currently the hardcoded GF(2**8).
* int32 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 gfGenerator; /* GF generator polynomial */
int32 *indexOf; /* log */
int32 *alphaTo; /* inverse log */
int32 *encAlphaTo; /* inverse log optimized for encoder */
} GaloisTables;
/* Lookup and working tables for the ReedSolomon codecs */
typedef struct _ReedSolomonTables
{ GaloisTables *gfTables;/* from above */
int32 *gpoly; /* RS code generator polynomial */
int32 fcr; /* first consecutive root of RS generator polynomial */
int32 primElem; /* primitive field element */
int32 nroots; /* degree of RS generator polynomial */
int32 ndata; /* data bytes per ecc block */
} ReedSolomonTables;
GaloisTables* CreateGaloisTables(int32);
void FreeGaloisTables(GaloisTables*);
ReedSolomonTables *CreateReedSolomonTables(GaloisTables*, int32, int32, int);
void FreeReedSolomonTables(ReedSolomonTables*);
/***
*** l-ec.c
***/
#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*);
/***
*** misc.c
***/
char* sgettext(char*);
char* sgettext_utf8(char*);
int64 uchar_to_int64(unsigned char*);
void int64_to_uchar(unsigned char*, int64);
void CalcSectors(int64, int64*, int*);
/***
*** recover-raw.c
***/
#define CD_RAW_SECTOR_SIZE 2352
#define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */
int CheckEDC(const unsigned char*, bool);
int CheckMSF(unsigned char*, int);
int ValidateRawSector(unsigned char *frame, bool xaMode);
bool Init_LEC_Correct(void);
#endif /* DVDISASTER_H */

View File

@ -1,40 +0,0 @@
/* 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
*
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
*
* 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 "dvdisaster.h"
/*
* 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;
}

View File

@ -1,156 +0,0 @@
/* 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
*
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
*
* 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 "dvdisaster.h"
#include "galois-inlines.h"
/***
*** Galois field arithmetic.
***
* Calculations are done over the extension field GF(2**n).
* Be careful not to overgeneralize these arithmetics;
* they only work for the case of GF(p**n) with p being prime.
*/
/* Initialize the Galois field tables */
GaloisTables* CreateGaloisTables(int32 gf_generator)
{
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()
folded into the table. */
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));
/* create the log/ilog values */
for(b=1, log=0; log<GF_FIELDMAX; log++)
{ gt->indexOf[b] = log;
gt->alphaTo[log] = b;
b = b << 1;
if(b & GF_FIELDSIZE)
b = b ^ gf_generator;
}
if(b!=1)
{
printf("Failed to create the Galois field log tables!\n");
exit(1);
}
/* we're even closed using infinity (makes things easier) */
gt->indexOf[0] = GF_ALPHA0; /* log(0) = inf */
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)];
return gt;
}
void FreeGaloisTables(GaloisTables *gt)
{
if(gt->indexOf) free(gt->indexOf);
if(gt->alphaTo) free(gt->alphaTo);
if(gt->encAlphaTo) free(gt->encAlphaTo);
free(gt);
}
/***
*** Create the the Reed-Solomon generator polynomial
*** and some auxiliary data structures.
*/
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;
rt->gfTables = gt;
rt->fcr = first_consecutive_root;
rt->primElem = prim_elem;
rt->nroots = nroots_in;
rt->ndata = GF_FIELDMAX - rt->nroots;
rt->gpoly = (int32 *)calloc((rt->nroots+1), sizeof(int32));
/* Create the RS code generator polynomial */
rt->gpoly[0] = 1;
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) */
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)];
}
/* 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
return rt;
}
void FreeReedSolomonTables(ReedSolomonTables *rt)
{
if(rt->gpoly) free(rt->gpoly);
free(rt);
}

View File

@ -1,478 +0,0 @@
/* 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
*
* The Reed-Solomon error correction draws a lot of inspiration - and even code -
* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
*
* 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 "dvdisaster.h"
#include "galois-inlines.h"
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
/***
*** Mapping between cd frame and parity vectors
***/
/*
* Mapping of frame bytes to P/Q Vectors
*/
int PToByteIndex(int p, int i)
{ return 12 + p + i*86;
}
void ByteIndexToP(int b, int *p, int *i)
{ *p = (b-12)%86;
*i = (b-12)/86;
}
int QToByteIndex(int q, int i)
{ int offset = 12 + (q & 1);
if(i == 43) return 2248+q;
if(i == 44) return 2300+q;
q&=~1;
return offset + (q*43 + i*88) % 2236;
}
void ByteIndexToQ(int b, int *q, int *i)
{ int x,y,offset;
if(b >= 2300)
{ *i = 44;
*q = (b-2300);
return;
}
if(b >= 2248)
{ *i = 43;
*q = (b-2248);
return;
}
offset = b&1;
b = (b-12)/2;
x = b/43;
y = (b-(x*43))%26;
*i = b-(x*43);
*q = 2*((x+26-y)%26)+offset;
}
/*
* There are 86 vectors of P-parity, yielding a RS(26,24) code.
*/
void GetPVector(unsigned char *frame, unsigned char *data, int n)
{ int i;
int w_idx = n+12;
for(i=0; i<26; i++, w_idx+=86)
data[i] = frame[w_idx];
}
void SetPVector(unsigned char *frame, unsigned char *data, int n)
{ int i;
int w_idx = n+12;
for(i=0; i<26; i++, w_idx+=86)
frame[w_idx] = data[i];
}
void FillPVector(unsigned char *frame, unsigned char data, int n)
{ int i;
int w_idx = n+12;
for(i=0; i<26; i++, w_idx+=86)
frame[w_idx] = data;
}
void OrPVector(unsigned char *frame, unsigned char value, int n)
{ int i;
int w_idx = n+12;
for(i=0; i<26; i++, w_idx+=86)
frame[w_idx] |= value;
}
void AndPVector(unsigned char *frame, unsigned char value, int n)
{ int i;
int w_idx = n+12;
for(i=0; i<26; i++, w_idx+=86)
frame[w_idx] &= value;
}
/*
* There are 52 vectors of Q-parity, yielding a RS(45,43) code.
*/
void GetQVector(unsigned char *frame, unsigned char *data, int n)
{ int offset = 12 + (n & 1);
int w_idx = (n&~1) * 43;
int i;
for(i=0; i<43; i++, w_idx+=88)
data[i] = frame[(w_idx % 2236) + offset];
data[43] = frame[2248 + n];
data[44] = frame[2300 + n];
}
void SetQVector(unsigned char *frame, unsigned char *data, int n)
{ int offset = 12 + (n & 1);
int w_idx = (n&~1) * 43;
int i;
for(i=0; i<43; i++, w_idx+=88)
frame[(w_idx % 2236) + offset] = data[i];
frame[2248 + n] = data[43];
frame[2300 + n] = data[44];
}
void FillQVector(unsigned char *frame, unsigned char data, int n)
{ int offset = 12 + (n & 1);
int w_idx = (n&~1) * 43;
int i;
for(i=0; i<43; i++, w_idx+=88)
frame[(w_idx % 2236) + offset] = data;
frame[2248 + n] = data;
frame[2300 + n] = data;
}
void OrQVector(unsigned char *frame, unsigned char data, int n)
{ int offset = 12 + (n & 1);
int w_idx = (n&~1) * 43;
int i;
for(i=0; i<43; i++, w_idx+=88)
frame[(w_idx % 2236) + offset] |= data;
frame[2248 + n] |= data;
frame[2300 + n] |= data;
}
void AndQVector(unsigned char *frame, unsigned char data, int n)
{ int offset = 12 + (n & 1);
int w_idx = (n&~1) * 43;
int i;
for(i=0; i<43; i++, w_idx+=88)
frame[(w_idx % 2236) + offset] &= data;
frame[2248 + n] &= data;
frame[2300 + n] &= data;
}
/***
*** C2 error counting
***/
int CountC2Errors(unsigned char *frame)
{ int i,count = 0;
frame += 2352;
for(i=0; i<294; i++, frame++)
{ if(*frame & 0x01) count++;
if(*frame & 0x02) count++;
if(*frame & 0x04) count++;
if(*frame & 0x08) count++;
if(*frame & 0x10) count++;
if(*frame & 0x20) count++;
if(*frame & 0x40) count++;
if(*frame & 0x80) count++;
}
return count;
}
/***
*** L-EC error correction for CD raw data sectors
***/
/*
* These could be used from ReedSolomonTables,
* but hardcoding them is faster.
*/
#define NROOTS 2
#define LEC_FIRST_ROOT 0 //GF_ALPHA0
#define LEC_PRIM_ELEM 1
#define LEC_PRIMTH_ROOT 1
/*
* Calculate the error syndrome
*/
int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
int *erasure_list, int erasure_count)
{ GaloisTables *gt = rt->gfTables;
int syndrome[NROOTS];
int lambda[NROOTS+1];
int omega[NROOTS+1];
int b[NROOTS+1];
int reg[NROOTS+1];
int root[NROOTS];
int loc[NROOTS];
int syn_error;
int deg_lambda,lambda_roots;
int deg_omega;
int shortened_size = GF_FIELDMAX - 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];
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)];
/*** Convert syndrome to index form, check for nonzero condition. */
syn_error = 0;
for(i=0; i<NROOTS; i++)
{ syn_error |= syndrome[i];
syndrome[i] = gt->indexOf[syndrome[i]];
}
/*** If the syndrome is zero, everything is fine. */
if(!syn_error)
return 0;
/*** Initialize lambda to be the erasure locator polynomial */
lambda[0] = 1;
lambda[1] = lambda[2] = 0;
erasure_list[0] += padding;
erasure_list[1] += padding;
if(erasure_count > 2) /* sanity check */
erasure_count = 0;
if(erasure_count > 0)
{ lambda[1] = gt->alphaTo[mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[0]))];
for(i=1; i<erasure_count; i++)
{ 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]];
if(tmp != GF_ALPHA0)
lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
}
}
}
for(i=0; i<NROOTS+1; i++)
b[i] = gt->indexOf[lambda[i]];
/*** Berlekamp-Massey algorithm to determine error+erasure locator polynomial */
r = erasure_count; /* r is the step number */
el = erasure_count;
/* Compute discrepancy at the r-th step in poly-form */
while(++r <= NROOTS)
{ 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])];
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;
}
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];
}
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;
}
memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
}
}
/*** Convert lambda to index form and compute deg(lambda(x)) */
deg_lambda = 0;
for(i=0; i<NROOTS+1; i++)
{ lambda[i] = gt->indexOf[lambda[i]];
if(lambda[i] != GF_ALPHA0)
deg_lambda = i;
}
/*** Find roots of the error+erasure locator polynomial by Chien search */
memcpy(reg+1, lambda+1, NROOTS*sizeof(reg[0]));
lambda_roots = 0; /* Number of roots of lambda(x) */
for(i=1, k=LEC_PRIMTH_ROOT-1; i<=GF_FIELDMAX; i++, k=mod_fieldmax(k+LEC_PRIMTH_ROOT))
{ int q=1; /* lambda[0] is always 0 */
for(j=deg_lambda; j>0; j--)
{ if(reg[j] != GF_ALPHA0)
{ reg[j] = mod_fieldmax(reg[j] + j);
q ^= gt->alphaTo[reg[j]];
}
}
if(q != 0) continue; /* Not a root */
/* store root in index-form and the error location number */
root[lambda_roots] = i;
loc[lambda_roots] = k;
/* If we've already found max possible roots, abort the search to save time */
if(++lambda_roots == deg_lambda) break;
}
/* deg(lambda) unequal to number of roots => uncorrectable error detected
This is not reliable for very small numbers of roots, e.g. nroots = 2 */
if(deg_lambda != lambda_roots)
{ return -1;
}
/* Compute err+eras evaluator poly omega(x) = syn(x)*lambda(x)
(modulo x**nroots). in index form. Also find deg(omega). */
deg_omega = deg_lambda-1;
for(i=0; i<=deg_omega; i++)
{ int tmp = 0;
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])];
}
omega[i] = gt->indexOf[tmp];
}
/* Compute error values in poly-form.
num1 = omega(inv(X(l))),
num2 = inv(X(l))**(FIRST_ROOT-1) and
den = lambda_pr(inv(X(l))) all in poly-form. */
for(j=lambda_roots-1; j>=0; j--)
{ int num1 = 0;
int num2;
int den;
int location = loc[j];
for(i=deg_omega; i>=0; i--)
{ if(omega[i] != GF_ALPHA0)
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])];
}
/* 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])];
/* 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 1
else return -3;
#endif
}
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
for(i=0; i<NROOTS; i++)
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)];
}
/*** Convert syndrome to index form, check for nonzero condition. */
#if 1
for(i=0; i<NROOTS; i++)
if(syndrome[i])
return -2;
#endif
return corrected;
}

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

@ -1,77 +0,0 @@
/* cdrdao - write audio CD-Rs in disc-at-once mode
*
* Copyright (C) 1998-2002 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __LEC_H__
#define __LEC_H__
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <inttypes.h>
typedef uint32_t u_int32_t;
typedef uint16_t u_int16_t;
typedef uint8_t u_int8_t;
#ifndef TRUE
#define TRUE 1
#endif
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* Scrambles and byte swaps an encoded sector.
* 'sector' must be 2352 byte wide.
*/
void lec_scramble(u_int8_t *sector);
#endif

View File

@ -1,210 +0,0 @@
/* 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
*
* 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 "dvdisaster.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);
return(1);
}
/***
*** CD level CRC calculation
***/
/*
* Test raw sector against its 32bit CRC.
* Returns TRUE if frame is good.
*/
int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
{
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;
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);
}
}
/***
*** A very simple L-EC error correction.
***
* Perform just one pass over the Q and P vectors to see if everything
* is okay respectively correct minor errors. This is pretty much the
* same stuff the drive is supposed to do in the final L-EC stage.
*/
static int simple_lec(unsigned char *frame)
{
unsigned char byte_state[2352];
unsigned char p_vector[P_VECTOR_SIZE];
unsigned char q_vector[Q_VECTOR_SIZE];
unsigned char p_state[P_VECTOR_SIZE];
int erasures[Q_VECTOR_SIZE], erasure_count;
int ignore[2];
int p_failures, q_failures;
int p_corrected, q_corrected;
int p,q;
/* Setup */
memset(byte_state, 0, 2352);
p_failures = q_failures = 0;
p_corrected = q_corrected = 0;
/* Perform Q-Parity error correction */
for(q=0; q<N_Q_VECTORS; q++)
{ int err;
/* We have no erasure information for Q vectors */
GetQVector(frame, q_vector, q);
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
/* 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++;
}
}
}
/* Perform P-Parity error correction */
for(p=0; p<N_P_VECTORS; p++)
{ int err,i;
/* Try error correction without erasure information */
GetPVector(frame, p_vector, p);
err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
/* If unsuccessful, try again using erasures.
Erasure information is uncertain, so try this last. */
if(err < 0 || err > 2)
{ 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;
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++;
}
else /* Correctable. */
{ 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 0;
}
/***
*** Validate CD raw sector
***/
int ValidateRawSector(unsigned char *frame, bool xaMode)
{
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. */
if(!CheckEDC(frame, xaMode))
{
unsigned char header[4];
if(xaMode)
{
memcpy(header, frame + 12, 4);
memset(frame + 12, 0, 4);
}
lec_did_sth = simple_lec(frame);
if(xaMode)
memcpy(frame + 12, header, 4);
}
/* Test internal sector checksum again */
if(!CheckEDC(frame, xaMode))
{
/* EDC failure in RAW sector */
return FALSE;
}
return TRUE;
}

View File

@ -1,259 +0,0 @@
/********************************************************
* *
* PC Engine CD Command 0xD8 - SAPSP *
* *
********************************************************/
static void DoNEC_PCE_SAPSP(const uint8 *cdb)
{
uint32 new_read_sec_start;
//printf("Set audio start: %02x %02x %02x %02x %02x %02x %02x\n", cdb[9], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6]);
switch (cdb[9] & 0xc0)
{
default: //SCSIDBG("Unknown SAPSP 9: %02x\n", cdb[9]);
case 0x00:
new_read_sec_start = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
break;
case 0x40:
new_read_sec_start = AMSF_to_LBA(BCD_to_U8(cdb[2]), BCD_to_U8(cdb[3]), BCD_to_U8(cdb[4]));
break;
case 0x80:
{
int track = BCD_to_U8(cdb[2]);
if(!track)
track = 1;
else if(track >= toc.last_track + 1)
track = 100;
new_read_sec_start = toc.tracks[track].lba;
}
break;
}
//printf("%lld\n", (long long)(monotonic_timestamp - pce_lastsapsp_timestamp) * 1000 / System_Clock);
if(cdda.CDDAStatus == CDDASTATUS_PLAYING && new_read_sec_start == read_sec_start && ((int64)(monotonic_timestamp - pce_lastsapsp_timestamp) * 1000 / System_Clock) < 190)
{
pce_lastsapsp_timestamp = monotonic_timestamp;
SendStatusAndMessage(STATUS_GOOD, 0x00);
CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE);
return;
}
pce_lastsapsp_timestamp = monotonic_timestamp;
read_sec = read_sec_start = new_read_sec_start;
read_sec_end = toc.tracks[100].lba;
cdda.CDDAReadPos = 588;
cdda.CDDAStatus = CDDASTATUS_PAUSED;
cdda.PlayMode = PLAYMODE_SILENT;
if(cdb[1])
{
cdda.PlayMode = PLAYMODE_NORMAL;
cdda.CDDAStatus = CDDASTATUS_PLAYING;
}
if(read_sec < toc.tracks[100].lba)
Cur_CDIF->HintReadSector(read_sec);
SendStatusAndMessage(STATUS_GOOD, 0x00);
CDIRQCallback(SCSICD_IRQ_DATA_TRANSFER_DONE);
}
/********************************************************
* *
* PC Engine CD Command 0xD9 - SAPEP *
* *
********************************************************/
static void DoNEC_PCE_SAPEP(const uint8 *cdb)
{
uint32 new_read_sec_end;
//printf("Set audio end: %02x %02x %02x %02x %02x %02x %02x\n", cdb[9], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6]);
switch (cdb[9] & 0xc0)
{
default: //SCSIDBG("Unknown SAPEP 9: %02x\n", cdb[9]);
case 0x00:
new_read_sec_end = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
break;
case 0x40:
new_read_sec_end = BCD_to_U8(cdb[4]) + 75 * (BCD_to_U8(cdb[3]) + 60 * BCD_to_U8(cdb[2]));
new_read_sec_end -= 150;
break;
case 0x80:
{
int track = BCD_to_U8(cdb[2]);
if(!track)
track = 1;
else if(track >= toc.last_track + 1)
track = 100;
new_read_sec_end = toc.tracks[track].lba;
}
break;
}
read_sec_end = new_read_sec_end;
switch(cdb[1]) // PCE CD(TODO: Confirm these, and check the mode mask):
{
default:
case 0x03: cdda.PlayMode = PLAYMODE_NORMAL;
cdda.CDDAStatus = CDDASTATUS_PLAYING;
break;
case 0x02: cdda.PlayMode = PLAYMODE_INTERRUPT;
cdda.CDDAStatus = CDDASTATUS_PLAYING;
break;
case 0x01: cdda.PlayMode = PLAYMODE_LOOP;
cdda.CDDAStatus = CDDASTATUS_PLAYING;
break;
case 0x00: cdda.PlayMode = PLAYMODE_SILENT;
cdda.CDDAStatus = CDDASTATUS_STOPPED;
break;
}
SendStatusAndMessage(STATUS_GOOD, 0x00);
}
/********************************************************
* *
* PC Engine CD Command 0xDA - Pause *
* *
********************************************************/
static void DoNEC_PCE_PAUSE(const uint8 *cdb)
{
if(cdda.CDDAStatus != CDDASTATUS_STOPPED) // Hmm, should we give an error if it tries to pause and it's already paused?
{
cdda.CDDAStatus = CDDASTATUS_PAUSED;
SendStatusAndMessage(STATUS_GOOD, 0x00);
}
else // Definitely give an error if it tries to pause when no track is playing!
{
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_AUDIO_NOT_PLAYING);
}
}
/********************************************************
* *
* PC Engine CD Command 0xDD - Read Subchannel Q *
* *
********************************************************/
static void DoNEC_PCE_READSUBQ(const uint8 *cdb)
{
uint8 *SubQBuf = cd.SubQBuf[QMode_Time];
uint8 data_in[8192];
memset(data_in, 0x00, 10);
data_in[2] = SubQBuf[1]; // Track
data_in[3] = SubQBuf[2]; // Index
data_in[4] = SubQBuf[3]; // M(rel)
data_in[5] = SubQBuf[4]; // S(rel)
data_in[6] = SubQBuf[5]; // F(rel)
data_in[7] = SubQBuf[7]; // M(abs)
data_in[8] = SubQBuf[8]; // S(abs)
data_in[9] = SubQBuf[9]; // F(abs)
if(cdda.CDDAStatus == CDDASTATUS_PAUSED)
data_in[0] = 2; // Pause
else if(cdda.CDDAStatus == CDDASTATUS_PLAYING || cdda.CDDAStatus == CDDASTATUS_SCANNING) // FIXME: Is this the correct status code for scanning playback?
data_in[0] = 0; // Playing
else
data_in[0] = 3; // Stopped
DoSimpleDataIn(data_in, 10);
}
/********************************************************
* *
* PC Engine CD Command 0xDE - Get Directory Info *
* *
********************************************************/
static void DoNEC_PCE_GETDIRINFO(const uint8 *cdb)
{
// Problems:
// Returned data lengths on real PCE are not confirmed.
// Mode 0x03 behavior not tested on real PCE
uint8 data_in[2048];
uint32 data_in_size = 0;
memset(data_in, 0, sizeof(data_in));
switch(cdb[1])
{
default: //MDFN_DispMessage("Unknown GETDIRINFO Mode: %02x", cdb[1]);
//printf("Unknown GETDIRINFO Mode: %02x", cdb[1]);
case 0x0:
data_in[0] = U8_to_BCD(toc.first_track);
data_in[1] = U8_to_BCD(toc.last_track);
data_in_size = 2;
break;
case 0x1:
{
uint8 m, s, f;
LBA_to_AMSF(toc.tracks[100].lba, &m, &s, &f);
data_in[0] = U8_to_BCD(m);
data_in[1] = U8_to_BCD(s);
data_in[2] = U8_to_BCD(f);
data_in_size = 3;
}
break;
case 0x2:
{
uint8 m, s, f;
int track = BCD_to_U8(cdb[2]);
if(!track)
track = 1;
else if(cdb[2] == 0xAA)
{
track = 100;
}
else if(track > 99)
{
CommandCCError(SENSEKEY_ILLEGAL_REQUEST, NSE_INVALID_PARAMETER);
return;
}
LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);
data_in[0] = U8_to_BCD(m);
data_in[1] = U8_to_BCD(s);
data_in[2] = U8_to_BCD(f);
data_in[3] = toc.tracks[track].control;
data_in_size = 4;
}
break;
}
DoSimpleDataIn(data_in, data_in_size);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,97 +0,0 @@
#ifndef __PCFX_SCSICD_H
#define __PCFX_SCSICD_H
typedef int32 scsicd_timestamp_t;
typedef struct
{
// Data bus(FIXME: we should have a variable for the target and the initiator, and OR them together to be truly accurate).
uint8 DB;
uint32 signals;
// Signals under our(the "target") control.
//bool BSY, MSG, CD, REQ, IO;
// Signals under the control of the initiator(not us!)
//bool kingACK, kingRST, kingSEL, kingATN;
} scsicd_bus_t;
extern scsicd_bus_t cd_bus; // Don't access this structure directly by name outside of scsicd.c, but use the macros below.
// Signals under our(the "target") control.
#define SCSICD_IO_mask 0x001
#define SCSICD_CD_mask 0x002
#define SCSICD_MSG_mask 0x004
#define SCSICD_REQ_mask 0x008
#define SCSICD_BSY_mask 0x010
// Signals under the control of the initiator(not us!)
#define SCSICD_kingRST_mask 0x020
#define SCSICD_kingACK_mask 0x040
#define SCSICD_kingATN_mask 0x080
#define SCSICD_kingSEL_mask 0x100
#define BSY_signal ((const bool)(cd_bus.signals & SCSICD_BSY_mask))
#define ACK_signal ((const bool)(cd_bus.signals & SCSICD_kingACK_mask))
#define RST_signal ((const bool)(cd_bus.signals & SCSICD_kingRST_mask))
#define MSG_signal ((const bool)(cd_bus.signals & SCSICD_MSG_mask))
#define SEL_signal ((const bool)(cd_bus.signals & SCSICD_kingSEL_mask))
#define REQ_signal ((const bool)(cd_bus.signals & SCSICD_REQ_mask))
#define IO_signal ((const bool)(cd_bus.signals & SCSICD_IO_mask))
#define CD_signal ((const bool)(cd_bus.signals & SCSICD_CD_mask))
#define ATN_signal ((const bool)(cd_bus.signals & SCSICD_kingATN_mask))
#define DB_signal ((const uint8)cd_bus.DB)
#define SCSICD_GetDB() DB_signal
#define SCSICD_GetBSY() BSY_signal
#define SCSICD_GetIO() IO_signal
#define SCSICD_GetCD() CD_signal
#define SCSICD_GetMSG() MSG_signal
#define SCSICD_GetREQ() REQ_signal
// Should we phase out getting these initiator-driven signals like this(the initiator really should keep track of them itself)?
#define SCSICD_GetACK() ACK_signal
#define SCSICD_GetRST() RST_signal
#define SCSICD_GetSEL() SEL_signal
#define SCSICD_GetATN() ATN_signal
void SCSICD_Power(scsicd_timestamp_t system_timestamp);
void SCSICD_SetDB(uint8 data);
// These SCSICD_Set* functions are kind of misnomers, at least in comparison to the SCSICD_Get* functions...
// They will set/clear the bits corresponding to the KING's side of the bus.
void SCSICD_SetACK(bool set);
void SCSICD_SetSEL(bool set);
void SCSICD_SetRST(bool set);
void SCSICD_SetATN(bool set);
uint32 SCSICD_Run(scsicd_timestamp_t);
void SCSICD_ResetTS(uint32 ts_base);
enum
{
SCSICD_PCE = 1,
SCSICD_PCFX
};
enum
{
SCSICD_IRQ_DATA_TRANSFER_DONE = 1,
SCSICD_IRQ_DATA_TRANSFER_READY,
SCSICD_IRQ_MAGICAL_REQ,
};
void SCSICD_GetCDDAValues(int16 &left, int16 &right);
void SCSICD_SetLog(void (*logfunc)(const char *, const char *, ...));
void SCSICD_Init(int type, int CDDATimeDiv, int32* left_hrbuf, int32* right_hrbuf, uint32 TransferRate, uint32 SystemClock, void (*IRQFunc)(int), void (*SSCFunc)(uint8, int)) MDFN_COLD;
void SCSICD_SetTransferRate(uint32 TransferRate);
void SCSICD_SetCDDAVolume(double left, double right);
void SCSICD_SetDisc(bool tray_open, CDIF *cdif, bool no_emu_side_effects = false);
#endif

View File

@ -1,69 +0,0 @@
// WARNING: Check resampling algorithm in scsicd.cpp for overflows if any value in here is negative.
/* -1 */ { 1777, 12211, 27812, 27640, 11965, 1703, 9, 0 }, // 83117 83119.332059(diff = 2.332059)
/* 0 */ { 1702, 11965, 27640, 27811, 12211, 1777, 11, 0 }, // 83117 83121.547903(diff = 4.547903)
/* 1 */ { 1630, 11720, 27463, 27977, 12459, 1854, 14, 0 }, // 83117 83123.444392(diff = 6.444392)
/* 2 */ { 1560, 11478, 27282, 28139, 12708, 1933, 17, 0 }, // 83117 83125.036510(diff = 8.036510)
/* 3 */ { 1492, 11238, 27098, 28296, 12959, 2014, 20, 0 }, // 83117 83126.338722(diff = 9.338722)
/* 4 */ { 1427, 11000, 26909, 28448, 13212, 2098, 23, 0 }, // 83117 83127.364983(diff = 10.364983)
/* 5 */ { 1363, 10764, 26716, 28595, 13467, 2185, 27, 0 }, // 83117 83128.128743(diff = 11.128743)
/* 6 */ { 1302, 10530, 26519, 28738, 13723, 2274, 31, 0 }, // 83117 83128.642956(diff = 11.642956)
/* 7 */ { 1242, 10299, 26319, 28876, 13981, 2365, 35, 0 }, // 83117 83128.920096(diff = 11.920096)
/* 8 */ { 1185, 10071, 26115, 29009, 14239, 2459, 39, 0 }, // 83117 83128.972128(diff = 11.972128)
/* 9 */ { 1129, 9844, 25907, 29137, 14499, 2556, 45, 0 }, // 83117 83128.810568(diff = 11.810568)
/* 10 */ { 1076, 9620, 25695, 29260, 14761, 2655, 50, 0 }, // 83117 83128.446456(diff = 11.446456)
/* 11 */ { 1024, 9399, 25481, 29377, 15023, 2757, 56, 0 }, // 83117 83127.890369(diff = 10.890369)
/* 12 */ { 975, 9180, 25263, 29489, 15287, 2861, 62, 0 }, // 83117 83127.152431(diff = 10.152431)
/* 13 */ { 927, 8964, 25041, 29596, 15552, 2968, 69, 0 }, // 83117 83126.242312(diff = 9.242312)
/* 14 */ { 880, 8750, 24817, 29698, 15818, 3078, 76, 0 }, // 83117 83125.169251(diff = 8.169251)
/* 15 */ { 836, 8539, 24590, 29794, 16083, 3191, 84, 0 }, // 83117 83123.942037(diff = 6.942037)
/* 16 */ { 793, 8331, 24359, 29884, 16350, 3307, 93, 0 }, // 83117 83122.569034(diff = 5.569034)
/* 17 */ { 752, 8125, 24126, 29969, 16618, 3425, 102, 0 }, // 83117 83121.058175(diff = 4.058175)
/* 18 */ { 712, 7923, 23890, 30049, 16886, 3546, 111, 0 }, // 83117 83119.416975(diff = 2.416975)
/* 19 */ { 674, 7723, 23651, 30123, 17154, 3670, 122, 0 }, // 83117 83117.652622(diff = 0.652622)
/* 20 */ { 638, 7526, 23410, 30191, 17422, 3797, 133, 0 }, // 83117 83115.771622(diff = 1.228378)
/* 21 */ { 603, 7331, 23167, 30254, 17691, 3927, 144, 0 }, // 83117 83113.780335(diff = 3.219665)
/* 22 */ { 569, 7140, 22922, 30310, 17960, 4059, 157, 0 }, // 83117 83111.684630(diff = 5.315370)
/* 23 */ { 537, 6951, 22674, 30361, 18229, 4195, 170, 0 }, // 83117 83109.489972(diff = 7.510028)
/* 24 */ { 506, 6766, 22424, 30407, 18497, 4334, 183, 0 }, // 83117 83107.201429(diff = 9.798571)
/* 25 */ { 477, 6583, 22172, 30446, 18766, 4475, 198, 0 }, // 83117 83104.823668(diff = 12.176332)
/* 26 */ { 449, 6403, 21919, 30479, 19034, 4619, 214, 0 }, // 83117 83102.360963(diff = 14.639037)
/* 27 */ { 422, 6226, 21664, 30507, 19301, 4767, 230, 0 }, // 83117 83099.817193(diff = 17.182807)
/* 28 */ { 396, 6053, 21407, 30529, 19568, 4917, 247, 0 }, // 83117 83097.195820(diff = 19.804180)
/* 29 */ { 372, 5882, 21148, 30545, 19834, 5071, 265, 0 }, // 83117 83094.499993(diff = 22.500007)
/* 30 */ { 348, 5714, 20888, 30555, 20100, 5227, 285, 0 }, // 83117 83091.732389(diff = 25.267611)
/* 31 */ { 326, 5549, 20627, 30559, 20365, 5386, 305, 0 }, // 83117 83088.895321(diff = 28.104679)
/* 32 */ { 305, 5386, 20365, 30559, 20627, 5549, 326, 0 }, // 83117 83088.895321(diff = 28.104679)
/* 33 */ { 285, 5227, 20100, 30555, 20888, 5714, 348, 0 }, // 83117 83091.732389(diff = 25.267611)
/* 34 */ { 265, 5071, 19834, 30545, 21148, 5882, 372, 0 }, // 83117 83094.499993(diff = 22.500007)
/* 35 */ { 247, 4917, 19568, 30529, 21407, 6053, 396, 0 }, // 83117 83097.195820(diff = 19.804180)
/* 36 */ { 230, 4767, 19301, 30507, 21664, 6226, 422, 0 }, // 83117 83099.817193(diff = 17.182807)
/* 37 */ { 214, 4619, 19034, 30479, 21919, 6403, 449, 0 }, // 83117 83102.360963(diff = 14.639037)
/* 38 */ { 198, 4475, 18766, 30446, 22172, 6583, 477, 0 }, // 83117 83104.823668(diff = 12.176332)
/* 39 */ { 183, 4334, 18497, 30407, 22424, 6766, 506, 0 }, // 83117 83107.201429(diff = 9.798571)
/* 40 */ { 170, 4195, 18229, 30361, 22674, 6951, 537, 0 }, // 83117 83109.489972(diff = 7.510028)
/* 41 */ { 157, 4059, 17960, 30310, 22922, 7140, 569, 0 }, // 83117 83111.684630(diff = 5.315370)
/* 42 */ { 144, 3927, 17691, 30254, 23167, 7331, 603, 0 }, // 83117 83113.780335(diff = 3.219665)
/* 43 */ { 133, 3797, 17422, 30191, 23410, 7526, 638, 0 }, // 83117 83115.771622(diff = 1.228378)
/* 44 */ { 122, 3670, 17154, 30123, 23651, 7723, 674, 0 }, // 83117 83117.652622(diff = 0.652622)
/* 45 */ { 111, 3546, 16886, 30049, 23890, 7923, 712, 0 }, // 83117 83119.416975(diff = 2.416975)
/* 46 */ { 102, 3425, 16618, 29969, 24126, 8125, 752, 0 }, // 83117 83121.058175(diff = 4.058175)
/* 47 */ { 93, 3307, 16350, 29884, 24359, 8331, 793, 0 }, // 83117 83122.569034(diff = 5.569034)
/* 48 */ { 84, 3191, 16083, 29794, 24590, 8539, 836, 0 }, // 83117 83123.942037(diff = 6.942037)
/* 49 */ { 76, 3078, 15818, 29698, 24817, 8750, 880, 0 }, // 83117 83125.169251(diff = 8.169251)
/* 50 */ { 69, 2968, 15552, 29596, 25041, 8964, 927, 0 }, // 83117 83126.242312(diff = 9.242312)
/* 51 */ { 62, 2861, 15287, 29489, 25263, 9180, 975, 0 }, // 83117 83127.152431(diff = 10.152431)
/* 52 */ { 56, 2757, 15023, 29377, 25481, 9399, 1024, 0 }, // 83117 83127.890369(diff = 10.890369)
/* 53 */ { 50, 2655, 14761, 29260, 25695, 9620, 1076, 0 }, // 83117 83128.446456(diff = 11.446456)
/* 54 */ { 45, 2556, 14499, 29137, 25907, 9844, 1129, 0 }, // 83117 83128.810568(diff = 11.810568)
/* 55 */ { 39, 2459, 14239, 29009, 26115, 10071, 1185, 0 }, // 83117 83128.972128(diff = 11.972128)
/* 56 */ { 35, 2365, 13981, 28876, 26319, 10299, 1242, 0 }, // 83117 83128.920096(diff = 11.920096)
/* 57 */ { 31, 2274, 13723, 28738, 26519, 10530, 1302, 0 }, // 83117 83128.642956(diff = 11.642956)
/* 58 */ { 27, 2185, 13467, 28595, 26716, 10764, 1363, 0 }, // 83117 83128.128743(diff = 11.128743)
/* 59 */ { 23, 2098, 13212, 28448, 26909, 11000, 1427, 0 }, // 83117 83127.364983(diff = 10.364983)
/* 60 */ { 20, 2014, 12959, 28296, 27098, 11238, 1492, 0 }, // 83117 83126.338722(diff = 9.338722)
/* 61 */ { 17, 1933, 12708, 28139, 27282, 11478, 1560, 0 }, // 83117 83125.036510(diff = 8.036510)
/* 62 */ { 14, 1854, 12459, 27977, 27463, 11720, 1630, 0 }, // 83117 83123.444392(diff = 6.444392)
/* 63 */ { 11, 1777, 12211, 27811, 27640, 11965, 1702, 0 }, // 83117 83121.547903(diff = 4.547903)
/* 64 */ { 9, 1703, 11965, 27640, 27812, 12211, 1777, 0 }, // 83117 83119.332059(diff = 2.332059)

View File

@ -1,123 +0,0 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <memory>
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
#define MDFN_FASTCALL
#define INLINE inline
#define MDFN_COLD
#define MDFN_HOT
#define NO_INLINE
#define NO_CLONE
#define MDFN_WARN_UNUSED_RESULT
#define MDFN_NOWARN_UNUSED __attribute__((unused))
#define MDFN_UNLIKELY(p) (p)
#define MDFN_LIKELY(p) (p)
//#define MDFN_ASSUME_ALIGNED(p, align) ((decltype(p))__builtin_assume_aligned((p), (align)))
#define MDFN_ASSUME_ALIGNED(p, align) (p)
#define trio_snprintf snprintf
#define trio_vprintf vprintf
#define trio_printf printf
#define trio_sprintf sprintf
#define TRUE true
#define FALSE false
#ifndef __alignas_is_defined
#define alignas(p)
#endif
#define override // remove for gcc 4.7
#define final
#define gettext_noop(s) (s)
#define MDFN_MASTERCLOCK_FIXED(n) ((int64)((double)(n) * (1LL << 32)))
static INLINE void MDFN_FastArraySet(uint32 *dst, const uint32 value, const size_t count)
{
uint32 *const end = dst + count;
while (dst < end)
*dst++ = value;
}
#define _(a) (a)
typedef struct
{
// Pitch(32-bit) must be equal to width and >= the "fb_width" specified in the MDFNGI struct for the emulated system.
// Height must be >= to the "fb_height" specified in the MDFNGI struct for the emulated system.
// The framebuffer pointed to by surface->pixels is written to by the system emulation code.
uint32 *pixels;
int pitch32;
// Pointer to an array of int32, number of elements = fb_height, set by the driver code. Individual elements written
// to by system emulation code. If the emulated system doesn't support multiple screen widths per frame, or if you handle
// such a situation by outputting at a constant width-per-frame that is the least-common-multiple of the screen widths, then
// you can ignore this. If you do wish to use this, you must set all elements every frame.
int32 *LineWidths;
// Pointer to sound buffer, set by the driver code, that the emulation code should render sound to.
int16 *SoundBuf;
// Number of cycles that this frame consumed, using MDFNGI::MasterClock as a time base.
// Set by emulation code.
int64 MasterCycles;
// Maximum size of the sound buffer, in frames. Set by the driver code.
int32 SoundBufMaxSize;
// Number of frames currently in internal sound buffer. Set by the system emulation code, to be read by the driver code.
int32 SoundBufSize;
// Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
// of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure
// is ignored while drawing the image.
int32 y, w, h;
// Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and
// only every other line in surface (with the start line defined by InterlacedField) has valid data
// (it's up to internal Mednafen code to deinterlace it).
bool InterlaceOn;
bool InterlaceField;
// if true, sip rendering
bool skip;
} EmulateSpecStruct;
#define MDFN_printf printf
#define MDFN_PrintError(...) printf
#include "endian.h"
#include "math_ops.h"
#include "../emulibc/emulibc.h"
#include "../emulibc/waterboxcore.h"
// settings
extern int Setting_HighDotclockWidth;
extern int Setting_CdSpeed;
extern int Setting_SlStart;
extern int Setting_SlEnd;
extern double Setting_ResampRateError;
extern int Setting_ResampQuality;
extern int Setting_CpuEmulation; // 0 = fast, 1 = accurate, 2 = auto
extern bool Setting_NoSpriteLimit;
extern bool Setting_AdpcmBuggy;
extern bool Setting_AdpcmNoClicks;
extern bool Setting_ChromaInterpolate;
extern int Setting_PortDevice[2];
extern bool Setting_PixelPro;

View File

@ -1,494 +0,0 @@
/******************************************************************************/
/* Mednafen - Multi-system Emulator */
/******************************************************************************/
/* endian.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_ENDIAN_H
#define __MDFN_ENDIAN_H
void Endian_A16_Swap(void *src, uint32 nelements);
void Endian_A32_Swap(void *src, uint32 nelements);
void Endian_A64_Swap(void *src, uint32 nelements);
void Endian_A16_NE_LE(void *src, uint32 nelements);
void Endian_A32_NE_LE(void *src, uint32 nelements);
void Endian_A64_NE_LE(void *src, uint32 nelements);
void Endian_A16_NE_BE(void *src, uint32 nelements);
void Endian_A32_NE_BE(void *src, uint32 nelements);
void Endian_A64_NE_BE(void *src, uint32 nelements);
void Endian_V_NE_LE(void* p, size_t len);
void Endian_V_NE_BE(void* p, size_t len);
//
//
//
static INLINE uint32 BitsExtract(const uint8* ptr, const size_t bit_offset, const size_t bit_count)
{
uint32 ret = 0;
for(size_t x = 0; x < bit_count; x++)
{
size_t co = bit_offset + x;
bool b = (ptr[co >> 3] >> (co & 7)) & 1;
ret |= (uint64)b << x;
}
return ret;
}
static INLINE void BitsIntract(uint8* ptr, const size_t bit_offset, const size_t bit_count, uint32 value)
{
for(size_t x = 0; x < bit_count; x++)
{
size_t co = bit_offset + x;
bool b = (value >> x) & 1;
uint8 tmp = ptr[co >> 3];
tmp &= ~(1 << (co & 7));
tmp |= b << (co & 7);
ptr[co >> 3] = tmp;
}
}
/*
Regarding safety of calling MDFN_*sb<true> on dynamically-allocated memory with new uint8[], see C++ standard 3.7.3.1(i.e. it should be
safe provided the offsets into the memory are aligned/multiples of the MDFN_*sb access type). malloc()'d and calloc()'d
memory should be safe as well.
Statically-allocated arrays/memory should be unioned with a big POD type or C++11 "alignas"'d. (May need to audit code to ensure
this is being done).
*/
static INLINE uint16 MDFN_bswap16(uint16 v)
{
return (v << 8) | (v >> 8);
}
static INLINE uint32 MDFN_bswap32(uint32 v)
{
return (v << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | (v >> 24);
}
static INLINE uint64 MDFN_bswap64(uint64 v)
{
return (v << 56) | (v >> 56) | ((v & 0xFF00) << 40) | ((v >> 40) & 0xFF00) | ((uint64)MDFN_bswap32(v >> 16) << 16);
}
#ifdef LSB_FIRST
#define MDFN_ENDIANH_IS_BIGENDIAN 0
#else
#define MDFN_ENDIANH_IS_BIGENDIAN 1
#endif
//
// X endian.
//
template<int isbigendian, typename T, bool aligned>
static INLINE T MDFN_deXsb(const void* ptr)
{
T tmp;
memcpy(&tmp, MDFN_ASSUME_ALIGNED(ptr, (aligned ? sizeof(T) : 1)), sizeof(T));
if(isbigendian != -1 && isbigendian != MDFN_ENDIANH_IS_BIGENDIAN)
{
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Gummy penguins.");
if(sizeof(T) == 8)
return MDFN_bswap64(tmp);
else if(sizeof(T) == 4)
return MDFN_bswap32(tmp);
else if(sizeof(T) == 2)
return MDFN_bswap16(tmp);
}
return tmp;
}
//
// Native endian.
//
template<typename T, bool aligned = false>
static INLINE T MDFN_densb(const void* ptr)
{
return MDFN_deXsb<-1, T, aligned>(ptr);
}
//
// Little endian.
//
template<typename T, bool aligned = false>
static INLINE T MDFN_delsb(const void* ptr)
{
return MDFN_deXsb<0, T, aligned>(ptr);
}
template<bool aligned = false>
static INLINE uint16 MDFN_de16lsb(const void* ptr)
{
return MDFN_delsb<uint16, aligned>(ptr);
}
static INLINE uint32 MDFN_de24lsb(const void* ptr)
{
const uint8* ptr_u8 = (const uint8*)ptr;
return (ptr_u8[0] << 0) | (ptr_u8[1] << 8) | (ptr_u8[2] << 16);
}
template<bool aligned = false>
static INLINE uint32 MDFN_de32lsb(const void* ptr)
{
return MDFN_delsb<uint32, aligned>(ptr);
}
template<bool aligned = false>
static INLINE uint64 MDFN_de64lsb(const void* ptr)
{
return MDFN_delsb<uint64, aligned>(ptr);
}
//
// Big endian.
//
template<typename T, bool aligned = false>
static INLINE T MDFN_demsb(const void* ptr)
{
return MDFN_deXsb<1, T, aligned>(ptr);
}
template<bool aligned = false>
static INLINE uint16 MDFN_de16msb(const void* ptr)
{
return MDFN_demsb<uint16, aligned>(ptr);
}
static INLINE uint32 MDFN_de24msb(const void* ptr)
{
const uint8* ptr_u8 = (const uint8*)ptr;
return (ptr_u8[0] << 16) | (ptr_u8[1] << 8) | (ptr_u8[2] << 0);
}
template<bool aligned = false>
static INLINE uint32 MDFN_de32msb(const void* ptr)
{
return MDFN_demsb<uint32, aligned>(ptr);
}
template<bool aligned = false>
static INLINE uint64 MDFN_de64msb(const void* ptr)
{
return MDFN_demsb<uint64, aligned>(ptr);
}
//
//
//
//
//
//
//
//
//
// X endian.
//
template<int isbigendian, typename T, bool aligned>
static INLINE void MDFN_enXsb(void* ptr, T value)
{
T tmp = value;
if(isbigendian != -1 && isbigendian != MDFN_ENDIANH_IS_BIGENDIAN)
{
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Gummy penguins.");
if(sizeof(T) == 8)
tmp = MDFN_bswap64(value);
else if(sizeof(T) == 4)
tmp = MDFN_bswap32(value);
else if(sizeof(T) == 2)
tmp = MDFN_bswap16(value);
}
memcpy(MDFN_ASSUME_ALIGNED(ptr, (aligned ? sizeof(T) : 1)), &tmp, sizeof(T));
}
//
// Native endian.
//
template<typename T, bool aligned = false>
static INLINE void MDFN_ennsb(void* ptr, T value)
{
MDFN_enXsb<-1, T, aligned>(ptr, value);
}
//
// Little endian.
//
template<typename T, bool aligned = false>
static INLINE void MDFN_enlsb(void* ptr, T value)
{
MDFN_enXsb<0, T, aligned>(ptr, value);
}
template<bool aligned = false>
static INLINE void MDFN_en16lsb(void* ptr, uint16 value)
{
MDFN_enlsb<uint16, aligned>(ptr, value);
}
static INLINE void MDFN_en24lsb(void* ptr, uint32 value)
{
uint8* ptr_u8 = (uint8*)ptr;
ptr_u8[0] = value >> 0;
ptr_u8[1] = value >> 8;
ptr_u8[2] = value >> 16;
}
template<bool aligned = false>
static INLINE void MDFN_en32lsb(void* ptr, uint32 value)
{
MDFN_enlsb<uint32, aligned>(ptr, value);
}
template<bool aligned = false>
static INLINE void MDFN_en64lsb(void* ptr, uint64 value)
{
MDFN_enlsb<uint64, aligned>(ptr, value);
}
//
// Big endian.
//
template<typename T, bool aligned = false>
static INLINE void MDFN_enmsb(void* ptr, T value)
{
MDFN_enXsb<1, T, aligned>(ptr, value);
}
template<bool aligned = false>
static INLINE void MDFN_en16msb(void* ptr, uint16 value)
{
MDFN_enmsb<uint16, aligned>(ptr, value);
}
static INLINE void MDFN_en24msb(void* ptr, uint32 value)
{
uint8* ptr_u8 = (uint8*)ptr;
ptr_u8[0] = value >> 16;
ptr_u8[1] = value >> 8;
ptr_u8[2] = value >> 0;
}
template<bool aligned = false>
static INLINE void MDFN_en32msb(void* ptr, uint32 value)
{
MDFN_enmsb<uint32, aligned>(ptr, value);
}
template<bool aligned = false>
static INLINE void MDFN_en64msb(void* ptr, uint64 value)
{
MDFN_enmsb<uint64, aligned>(ptr, value);
}
//
//
//
//
//
//
template<typename T, typename BT>
static INLINE uint8* ne16_ptr_be(BT* const base, const size_t byte_offset)
{
#ifdef MSB_FIRST
return (uint8*)base + (byte_offset &~ (sizeof(T) - 1));
#else
return (uint8*)base + (((byte_offset &~ (sizeof(T) - 1)) ^ (2 - std::min<size_t>(2, sizeof(T)))));
#endif
}
template<typename T>
static INLINE void ne16_wbo_be(uint16* const base, const size_t byte_offset, const T value)
{
uint8* const ptr = ne16_ptr_be<T>(base, byte_offset);
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
if(sizeof(T) == 4)
{
uint16* const ptr16 = (uint16*)ptr;
ptr16[0] = value >> 16;
ptr16[1] = value;
}
else
*(T*)ptr = value;
}
template<typename T>
static INLINE T ne16_rbo_be(const uint16* const base, const size_t byte_offset)
{
uint8* const ptr = ne16_ptr_be<T>(base, byte_offset);
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
if(sizeof(T) == 4)
{
uint16* const ptr16 = (uint16*)ptr;
T tmp;
tmp = ptr16[0] << 16;
tmp |= ptr16[1];
return tmp;
}
else
return *(T*)ptr;
}
template<typename T, bool IsWrite>
static INLINE void ne16_rwbo_be(uint16* const base, const size_t byte_offset, T* value)
{
if(IsWrite)
ne16_wbo_be<T>(base, byte_offset, *value);
else
*value = ne16_rbo_be<T>(base, byte_offset);
}
//
//
//
template<typename T, typename BT>
static INLINE uint8* ne16_ptr_le(BT* const base, const size_t byte_offset)
{
#ifdef LSB_FIRST
return (uint8*)base + (byte_offset &~ (sizeof(T) - 1));
#else
return (uint8*)base + (((byte_offset &~ (sizeof(T) - 1)) ^ (2 - std::min<size_t>(2, sizeof(T)))));
#endif
}
template<typename T>
static INLINE void ne16_wbo_le(uint16* const base, const size_t byte_offset, const T value)
{
uint8* const ptr = ne16_ptr_le<T>(base, byte_offset);
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
if(sizeof(T) == 4)
{
uint16* const ptr16 = (uint16*)ptr;
ptr16[0] = value;
ptr16[1] = value >> 16;
}
else
*(T*)ptr = value;
}
template<typename T>
static INLINE T ne16_rbo_le(const uint16* const base, const size_t byte_offset)
{
uint8* const ptr = ne16_ptr_le<T>(base, byte_offset);
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
if(sizeof(T) == 4)
{
uint16* const ptr16 = (uint16*)ptr;
T tmp;
tmp = ptr16[0];
tmp |= ptr16[1] << 16;
return tmp;
}
else
return *(T*)ptr;
}
template<typename T, bool IsWrite>
static INLINE void ne16_rwbo_le(uint16* const base, const size_t byte_offset, T* value)
{
if(IsWrite)
ne16_wbo_le<T>(base, byte_offset, *value);
else
*value = ne16_rbo_le<T>(base, byte_offset);
}
//
//
//
template<typename T>
static INLINE uint8* ne64_ptr_be(uint64* const base, const size_t byte_offset)
{
#ifdef MSB_FIRST
return (uint8*)base + (byte_offset &~ (sizeof(T) - 1));
#else
return (uint8*)base + (((byte_offset &~ (sizeof(T) - 1)) ^ (8 - sizeof(T))));
#endif
}
template<typename T>
static INLINE void ne64_wbo_be(uint64* const base, const size_t byte_offset, const T value)
{
uint8* const ptr = ne64_ptr_be<T>(base, byte_offset);
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Unsupported type size");
memcpy(MDFN_ASSUME_ALIGNED(ptr, sizeof(T)), &value, sizeof(T));
}
template<typename T>
static INLINE T ne64_rbo_be(uint64* const base, const size_t byte_offset)
{
uint8* const ptr = ne64_ptr_be<T>(base, byte_offset);
T ret;
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
memcpy(&ret, MDFN_ASSUME_ALIGNED(ptr, sizeof(T)), sizeof(T));
return ret;
}
template<typename T, bool IsWrite>
static INLINE void ne64_rwbo_be(uint64* const base, const size_t byte_offset, T* value)
{
if(IsWrite)
ne64_wbo_be<T>(base, byte_offset, *value);
else
*value = ne64_rbo_be<T>(base, byte_offset);
}
#endif

View File

@ -1,47 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* fxscsi.cpp:
** Copyright (C) 2009-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "pcfx.h"
#include "fxscsi.h"
namespace MDFN_IEN_PCFX
{
bool FXSCSI_Init(void)
{
return true;
}
uint8 FXSCSI_CtrlRead(uint32 A)
{
uint8 ret = 0; //rand();
//printf("FXSCSI: %08x(ret=%02x)\n", A, ret);
return(ret);
}
void FXSCSI_CtrlWrite(uint32 A, uint8 V)
{
printf("FXSCSI Write: %08x %02x\n", A, V);
}
}

View File

@ -1,33 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* fxscsi.h:
** Copyright (C) 2009-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_FXSCSI_H
#define __MDFN_FXSCSI_H
namespace MDFN_IEN_PCFX
{
bool FXSCSI_Init(void) MDFN_COLD;
uint8 FXSCSI_CtrlRead(uint32 A);
void FXSCSI_CtrlWrite(uint32 A, uint8 V);
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,530 +0,0 @@
#ifndef __PCE_VDC_H
#define __PCE_VDC_H
#define VDC_PIXEL_OUT_MASK 0x01FF
// This bit will be set for a non-sprite pixel if the BG layer is disabled(via ToggleLayer()),
#define VDC_BGDISABLE_OUT_MASK 0x0200
// HSync and VSync out bits are only valid when the EX bits in VDC's CR
// are set so that the VDC will output sync signals rather than
// input them. If it is not configured in this manner, the bit(s) shall always be 0.
#define VDC_HSYNC_OUT_MASK 0x2000
#define VDC_VSYNC_OUT_MASK 0x4000
// The DISP bit can either denote active display area(1 = active, 0 = inactive),
// colorburst insertion period(0 = insert colorburst, 1 = not in colorburst period; may not be emulated correctly),
// or "internal horizontal synchronous signal"(may not be emulated correctly), depending on the TE
// bits in the VDC's CR.
#define VDC_DISP_OUT_MASK 0x8000
#define VDC_REGSETP(_reg, _data, _msb) \
{ \
_reg &= 0xFF << ((_msb) ? 0 : 8); \
_reg |= (_data) << ((_msb) ? 8 : 0); \
}
#define VDC_REGGETP(_reg, _msb) ((_reg >> ((_msb) ? 8 : 0)) & 0xFF)
static const unsigned int vram_inc_tab[4] = {1, 32, 64, 128};
#define VDC_IS_BSY (pending_read || pending_write)
typedef struct
{
uint32 x;
uint32 flags;
uint8 palette_index;
uint16 pattern_data[4];
} SPRLE;
typedef struct
{
// In the case the VDC access doesn't cause a VRAM read/write, only ReadCount/WriteCount will be set to 0.
uint32 ReadStart;
uint32 ReadCount;
uint32 WriteStart;
uint32 WriteCount;
uint32 RegRWIndex;
bool RegWriteDone;
bool RegReadDone;
} VDC_SimulateResult;
class VDC
{
public:
VDC()
MDFN_COLD;
~VDC() MDFN_COLD;
// Default false.
void SetUnlimitedSprites(const bool nospritelimit);
// The VRAM size is specified in 16-bit words. Default 65536.
// Reset() should be called after changing this setting, otherwise things may be broken.
void SetVRAMSize(const uint32 par_VRAM_size);
int32 Reset(void) MDFN_WARN_UNUSED_RESULT;
// ResetSimulate(), SimulateWrite(), and SimulateRead() are intended to handle VRAM read/write breakpoints.
// SimulateWrite() and SimulateRead() will return the VRAM address that will EVENTUALLY be written(upper 32-bits) and/or read(lower 32-bits) to
// due to the access, or 0xFFFFFFFF in the upper or lower 32-bits if no VRAM access of that type occurs.
//
// The feature is intended to support block moves to VRAM in a single instruction. It may not function properly if the address passed to SimulateRead()
// or SimulateWrite() alternates(even if just once) between the data port high byte and control port between calls to ResetSimulate()
// Call to reset simulation state.
INLINE void ResetSimulate(void)
{
Simulate_MAWR = MAWR;
Simulate_MARR = MARR;
Simulate_select = select;
Simulate_CR = CR;
Simulate_LENR = LENR;
}
INLINE void SimulateRead(uint32 A, VDC_SimulateResult *result)
{
result->ReadCount = 0;
result->WriteCount = 0;
result->RegReadDone = false;
result->RegWriteDone = false;
if (A & 0x2)
{
result->RegReadDone = true;
result->RegRWIndex = Simulate_select;
}
if ((A & 0x3) == 0x3 && Simulate_select == 0x02)
{
Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
result->ReadStart = Simulate_MARR;
result->ReadCount = 1;
}
}
INLINE void SimulateWrite(uint32 A, uint8 V, VDC_SimulateResult *result)
{
result->ReadCount = 0;
result->WriteCount = 0;
result->RegReadDone = false;
result->RegWriteDone = false;
const unsigned int msb = A & 1;
switch (A & 0x3)
{
case 0x00:
Simulate_select = V & 0x1F;
break;
case 0x02:
case 0x03:
result->RegWriteDone = true;
result->RegRWIndex = Simulate_select;
switch (Simulate_select)
{
case 0x00:
VDC_REGSETP(Simulate_MAWR, V, msb);
break;
case 0x01:
VDC_REGSETP(Simulate_MARR, V, msb);
Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
result->ReadStart = Simulate_MARR;
result->ReadCount = 1;
break;
case 0x02:
if (msb)
{
result->WriteStart = Simulate_MAWR;
result->WriteCount = 1;
Simulate_MAWR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
}
break;
case 0x12:
VDC_REGSETP(Simulate_LENR, V, msb);
if (msb)
{
result->ReadStart = SOUR;
result->ReadCount = Simulate_LENR + 1;
if (DCR & 0x4)
result->ReadStart = (result->ReadStart - (result->ReadCount - 1)) & 0xFFFF;
result->WriteStart = DESR;
result->WriteCount = Simulate_LENR + 1;
if (DCR & 0x8)
result->WriteStart = (result->WriteStart - (result->WriteCount - 1)) & 0xFFFF;
}
break;
}
break;
}
}
INLINE void SimulateRead16(bool A, VDC_SimulateResult *result)
{
result->ReadCount = 0;
result->WriteCount = 0;
result->RegReadDone = false;
result->RegWriteDone = false;
if (A & 0x2)
{
result->RegReadDone = true;
result->RegRWIndex = Simulate_select;
}
if (A && Simulate_select == 0x02)
{
Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
result->ReadStart = Simulate_MARR;
result->ReadCount = 1;
}
}
INLINE void SimulateWrite16(bool A, uint16 V, VDC_SimulateResult *result)
{
result->ReadCount = 0;
result->WriteCount = 0;
result->RegReadDone = false;
result->RegWriteDone = false;
if (!A)
Simulate_select = V & 0x1F;
else
{
result->RegWriteDone = true;
result->RegRWIndex = Simulate_select;
switch (Simulate_select)
{
case 0x00:
Simulate_MAWR = V;
break;
case 0x01:
Simulate_MARR = V;
Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
result->ReadStart = Simulate_MARR;
result->ReadCount = 1;
break;
case 0x02:
result->WriteStart = Simulate_MAWR;
result->WriteCount = 1;
Simulate_MAWR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
break;
case 0x12:
Simulate_LENR = V;
result->ReadStart = SOUR;
result->ReadCount = Simulate_LENR + 1;
if (DCR & 0x4)
result->ReadStart = (result->ReadStart - (result->ReadCount - 1)) & 0xFFFF;
result->WriteStart = DESR;
result->WriteCount = Simulate_LENR + 1;
if (DCR & 0x8)
result->WriteStart = (result->WriteStart - (result->WriteCount - 1)) & 0xFFFF;
break;
}
}
}
int32 HSync(bool);
int32 VSync(bool);
void Write(uint32 A, uint8 V, int32 &next_event);
uint8 Read(uint32 A, int32 &next_event, bool peek = FALSE);
void Write16(bool A, uint16 V);
uint16 Read16(bool A, bool peek = FALSE);
int32 Run(int32 clocks, /*bool hs, bool vs,*/ uint16 *pixels, bool skip);
void FixTileCache(uint16);
void SetLayerEnableMask(uint64 mask);
void RunDMA(int32, bool force_completion = FALSE);
void RunSATDMA(int32, bool force_completion = FALSE);
void IncRCR(void);
void DoVBIRQTest(void);
void HDS_Start(void);
// Peek(VRAM/SAT) and Poke(VRAM/SAT) work in 16-bit VRAM word units.
INLINE uint16 PeekVRAM(uint16 Address)
{
if (Address < VRAM_Size)
return (VRAM[Address]);
else
return (0);
}
INLINE uint16 PeekSAT(uint8 Address)
{
return (SAT[Address]);
}
INLINE void PokeVRAM(uint16 Address, const uint16 Data)
{
if (Address < VRAM_Size)
{
VRAM[Address] = Data;
FixTileCache(Address);
}
}
INLINE void PokeSAT(uint8 Address, const uint16 Data)
{
SAT[Address] = Data;
}
// Register enums for GetRegister() and SetRegister()
enum
{
GSREG_MAWR = 0,
GSREG_MARR,
GSREG_CR,
GSREG_RCR,
GSREG_BXR,
GSREG_BYR,
GSREG_MWR,
GSREG_HSR,
GSREG_HDR,
GSREG_VSR,
GSREG_VDR,
GSREG_VCR,
GSREG_DCR,
GSREG_SOUR,
GSREG_DESR,
GSREG_LENR,
GSREG_DVSSR,
GSREG_SELECT,
GSREG_STATUS,
__GSREG_COUNT
};
// Pass NULL if you don't want more information about the special meaning of the value in the specified
// register. Otherwise, pass a buffer of at least 256 bytes in size.
uint32 GetRegister(const unsigned int id, char *special, const uint32 special_len);
void SetRegister(const unsigned int id, const uint32 value);
#ifdef WANT_DEBUGGER
bool DoGfxDecode(uint32 *target, const uint32 *color_table, const uint32 TransparentColor, bool DecodeSprites,
int32 w, int32 h, int32 scroll);
#endif
INLINE bool PeekIRQ(void)
{
return ((bool)(status & 0x3F));
}
INLINE void SetIRQHook(void (*irqh)(bool))
{
IRQHook = irqh;
}
INLINE void SetWSHook(bool (*wsh)(int32))
{
WSHook = wsh;
}
INLINE uint16_t* GetVramPointer()
{
return VRAM;
}
INLINE int GetVramByteSize()
{
return VRAM_Size * 2;
}
private:
int TimeFromHDSStartToBYRLatch(void);
int TimeFromBYRLatchToBXRLatch(void);
enum
{
HPHASE_HDS = 0,
HPHASE_HDS_PART2,
HPHASE_HDS_PART3,
HPHASE_HDW,
HPHASE_HDW_FINAL,
HPHASE_HDE,
HPHASE_HSW,
HPHASE_COUNT
};
enum
{
VPHASE_VDS = 0,
VPHASE_VDW,
VPHASE_VCR,
VPHASE_VSW,
VPHASE_COUNT
};
int VRAM_Size; // = 0x8000;
int VRAM_SizeMask; // = VRAM_Size - 1; //0x7FFF;
int VRAM_BGTileNoMask; // = VRAM_SizeMask / 16; //0x7FF;
void (*IRQHook)(bool);
bool (*WSHook)(int32);
void DoWaitStates(void);
void CheckAndCommitPending(void);
INLINE int32 CalcNextEvent(void)
{
int32 next_event = HPhaseCounter;
if (sat_dma_counter > 0 && sat_dma_counter < next_event)
next_event = sat_dma_counter;
if (sprite_cg_fetch_counter > 0 && sprite_cg_fetch_counter < next_event)
next_event = sprite_cg_fetch_counter;
if (DMARunning)
{
assert(VDMA_CycleCounter < 2);
int32 next_vram_dma_event = ((LENR + 1) * 4) - (DMAReadWrite * 2) - VDMA_CycleCounter;
assert(next_vram_dma_event > 0);
if (next_vram_dma_event > 0 && next_vram_dma_event < next_event)
next_event = next_vram_dma_event;
//printf("Next VRAM DMA event: %d(LENR = %d)\n", next_vram_dma_event, LENR);
}
assert(next_event > 0);
return (next_event);
}
bool in_exhsync, in_exvsync;
void CalcWidthStartEnd(uint32 &display_width, uint32 &start, uint32 &end);
void DrawBG(uint16 *target, int enabled);
void DrawSprites(uint16 *target, int enabled);
void FetchSpriteData(void);
uint8 Simulate_select;
uint16 Simulate_MAWR;
uint16 Simulate_MARR;
uint16 Simulate_CR;
uint16 Simulate_LENR;
int32 sat_dma_counter;
uint8 select;
uint16 MAWR; // Memory Address Write Register
uint16 MARR; // Memory Address Read Register
uint16 CR; // Control Register
uint16 CR_cache; // Cache for BG/SPR enable
uint16 RCR; // Raster Compare Register
uint16 BXR; // Background X-Scroll Register
uint16 BYR; // Background Y-Scroll Register
uint16 MWR; // Memory Width Register
uint16 HSR; // Horizontal Sync Register
uint16 HDR; // Horizontal Display Register
uint16 VSR;
uint16 VDR;
uint16 VCR;
uint16 DCR;
uint16 SOUR;
uint16 DESR;
uint16 LENR;
uint16 DVSSR;
// Internal SAT DMA transfer variables.
//uint16 SAT_SOUR;
//uint16 SAT_DESR;
//uint16 SAT_LENR;
int32 VDMA_CycleCounter;
uint32 RCRCount;
bool pending_read;
uint16 pending_read_addr;
uint16 read_buffer;
uint8 write_latch; // LSB
bool pending_write;
uint16 pending_write_addr;
uint16 pending_write_latch;
uint8 status;
uint16 SAT[0x100];
uint16 VRAM[65536]; //VRAM_Size];
union {
uint64 bg_tile_cache64[65536 / 16][8]; // Tile, y, x
uint8 bg_tile_cache[65536 / 16][8][8];
};
uint16 DMAReadBuffer;
bool DMAReadWrite;
bool DMARunning;
bool DMAPending;
bool SATBPending;
bool burst_mode;
uint32 BG_YOffset; // Reloaded from BYR at start of display area?
uint32 BG_XOffset; // Reloaded from BXR at each scanline, methinks.
uint32 HSW_cache, HDS_cache, HDW_cache, HDE_cache;
uint32 VDS_cache;
uint32 VSW_cache;
uint32 VDW_cache;
uint32 VCR_cache;
uint16 MWR_cache;
uint32 BG_YMoo;
bool NeedRCRInc, NeedVBIRQTest, NeedSATDMATest, NeedBGYInc;
int HPhase, VPhase;
int32 HPhaseCounter, VPhaseCounter;
int32 sprite_cg_fetch_counter;
int32 mystery_counter;
bool mystery_phase;
uint16 linebuf[1024 + 512];
uint32 pixel_desu;
int32 pixel_copy_count;
uint32 userle; // User layer enable.
bool unlimited_sprites;
int active_sprites;
SPRLE SpriteList[64 * 2]; // (see unlimited_sprites option, *2 to accommodate 32-pixel-width sprites ) //16];
};
#endif

View File

@ -1,260 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* huc6273.cpp - Unfinished emulation of the HuC6273, 3D chip in the PC-FXGA
** Copyright (C) 2007-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* Definitions:
CMT = Command Macro Table
*/
#include "pcfx.h"
#include "huc6273.h"
namespace MDFN_IEN_PCFX
{
enum
{
OP_NOP = 0x00,
OP_TRIANGLE_STRIP = 0x01,
OP_TRIANGLE_LIST = 0x02,
OP_POLY_LINE = 0x03,
OP_LINE_LIST = 0x04,
OP_RESERVED0 = 0x05,
OP_PUT_IMAGE = 0x06,
OP_READ_PIXEL = 0x07,
OP_WRITE_TE_REGISTERS = 0x08,
OP_WRITE_PE_REGISTERS = 0x09,
OP_MISC = 0x0A,
OP_RESERVED1 = 0x0B,
OP_READ_TE_REGISTERS = 0x0C,
OP_READ_PE_REGISTERS = 0x0D,
OP_WRITE_LUT = 0x0E,
OP_READ_LUT = 0x0F,
};
enum
{
INT_RHIT = 15, // Raster Hit
INT_HBL = 14, // H blank
INT_VBL = 13, // V blank
INT_HSY = 12, // H sync
INT_VSY = 11, // V sync
INT_RBDONE = 10, // Read back done
INT_TESYNC = 9, // TE Sync
INT_SPDONE = 8, // Sprite done
INT_CMDONE = 7, // Command macro done
INT_PESYNC = 6, // PE sync
INT_AEMP = 5, // Almost empty
INT_CSE = 4, // Command sync error
INT_AFL = 3, // Almost full
INT_OVF = 2, // Overflow
INT_FSY = 1, // Frame sync
};
static uint16 FIFO[0x20];
static uint8 InFIFO;
#define AFW (0x20 - InFIFO)
#define AEMPWD ((FIFOControl >> 4) & 0xFF)
#define AFLWD (FIFOControl & 0xF)
static uint16 FIFOControl; // 0x00004
static uint8 CMTBankSelect;
static uint16 CMTStartAddress;
static uint16 CMTByteCount;
static uint16 InterruptMask;
static uint16 InterruptStatus;
static uint16 ReadBack;
static uint16 HorizontalTiming, VerticalTiming;
static uint16 SCTAddressHi;
static uint16 SpriteControl;
static uint16 CDResult[2];
static uint16 SPWindowX[2]; // left and right
static uint16 SPWindowY[2]; // top and bottom
static uint16 MiscStatus;
static uint16 ErrorStatus; // Read only!
static uint16 DisplayControl;
static uint16 StatusControl;
static uint16 Config;
static uint16 RasterHit;
static uint16 Results[0x10];
static void CheckIRQ(void)
{
//uint16 MaskedResults = InterruptStatus & InterruptMask;
}
static void ProcessFIFO(void)
{
uint8 length = FIFO[0] & 0xFF;
if(length > 0x20)
{
length = 0x20;
puts("Length too long");
}
if(InFIFO >= length)
{
int opcode = FIFO[0] >> 12;
int option = (FIFO[0] >> 8) & 0x0F;
printf("Op: %02x, option: %02x\n", opcode, option);
InFIFO -= length;
for(int i = 0; i < InFIFO; i++)
FIFO[i] = FIFO[length + i];
}
}
static void StoreInFIFO(uint16 V)
{
if(AFW > 0)
{
FIFO[InFIFO] = V;
InFIFO++;
ProcessFIFO();
}
}
uint8 HuC6273_Read8(uint32 A)
{
puts("73 Read8");
return(0);
}
uint16 HuC6273_Read16(uint32 A)
{
A &= 0xfffff;
printf("HuC6273 Read: %04x\n", A);
switch(A)
{
case 0x00000:
case 0x00002: return(AFW); // Command FIFO status
case 0x00004: return(FIFOControl);
case 0x00006: return(CMTBankSelect);
case 0x00008: return(CMTStartAddress);
case 0x0000A: return(CMTByteCount);
case 0x0000C: return(InterruptMask);
case 0x0000E: return(0);
case 0x00010: return(InterruptStatus);
case 0x00012: return(ReadBack);
case 0x00014: return(HorizontalTiming);
case 0x00016: return(VerticalTiming);
case 0x00018: return(SCTAddressHi);
case 0x0001A: return(SpriteControl);
case 0x0001C: return(CDResult[0]);
case 0x0001E: return(CDResult[1]);
case 0x00020: return(SPWindowX[0]);
case 0x00022: return(SPWindowY[0]);
case 0x00024: return(SPWindowX[1]);
case 0x00026: return(SPWindowY[1]);
case 0x00028: return(MiscStatus);
case 0x0002A: return(ErrorStatus);
case 0x0002C: return(DisplayControl);
case 0x0002E: return(Config);
}
if(A >= 0x00060 && A <= 0x0007E)
{
return(Results[(A >> 1) & 0xF]);
}
return(0);
}
void HuC6273_Write16(uint32 A, uint16 V)
{
A &= 0xfffff;
printf("HuC6273 Write: %04x:%04x\n", A, V);
switch(A)
{
case 0x00000:
case 0x00002: StoreInFIFO(V); break;
case 0x00004: FIFOControl = V; break;
case 0x00006: CMTBankSelect = V & 0x1F; break;
case 0x00008: CMTStartAddress = V & 0xFFFE; break;
case 0x0000A: CMTByteCount = V & 0xFFFE; break;
case 0x0000C: InterruptMask = V;
CheckIRQ();
break;
case 0x0000E: // Interrupt Clear
CheckIRQ();
break;
case 0x00010: InterruptStatus = V;
CheckIRQ();
break;
case 0x00012: ReadBack = V; break;
case 0x00014: HorizontalTiming = V; break;
case 0x00016: VerticalTiming = V; break;
case 0x00018: SCTAddressHi = V; break;
case 0x0001A: SpriteControl = V; break;
case 0x0001C: CDResult[0] = V; break;
case 0x0001E: CDResult[1] = V; break;
case 0x00020: SPWindowX[0] = V; break; // X Left
case 0x00022: SPWindowY[0] = V; break; // Y Top
case 0x00024: SPWindowX[1] = V; break; // X Right
case 0x00026: SPWindowY[1] = V; break; // Y Bottom
case 0x00028: MiscStatus = V; break;
case 0x0002C: DisplayControl = V; break;
case 0x0002E: StatusControl = V; break;
case 0x0003C: RasterHit = V; break;
}
}
void HuC6273_Write8(uint32 A, uint8 V)
{
puts("73 Write8");
}
void HuC6273_Reset(void)
{
InFIFO = 0;
FIFOControl = 0x5 | (0x20 << 4);
}
bool HuC6273_Init(void)
{
return(TRUE);
}
}

View File

@ -1,38 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* huc6273.h:
** Copyright (C) 2007-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PCFX_HUC6273_H
#define __PCFX_HUC6273_H
namespace MDFN_IEN_PCFX
{
bool HuC6273_Init(void) MDFN_COLD;
uint8 HuC6273_Read8(uint32 A);
uint16 HuC6273_Read16(uint32 A);
void HuC6273_Write16(uint32 A, uint16 V);
void HuC6273_Write8(uint32 A, uint8 V);
void HuC6273_Reset(void) MDFN_COLD;
}
#endif

View File

@ -1,340 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* input.cpp:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "pcfx.h"
#include "interrupt.h"
#include "input.h"
#include "input/gamepad.h"
#include "input/mouse.h"
namespace MDFN_IEN_PCFX
{
#define PCFX_PORTS 2
#define TOTAL_PORTS 8
#define TAP_PORTS 4
static const int TapMap[2][TAP_PORTS] =
{
{0, 2, 3, 4},
{1, 5, 6, 7},
};
static void RemakeDevices(int which = -1);
static uint8 MultiTapEnabled;
// Mednafen-specific input type numerics
enum
{
FXIT_NONE = 0,
FXIT_GAMEPAD = 1,
FXIT_MOUSE = 2,
};
PCFX_Input_Device::~PCFX_Input_Device()
{
}
uint32 PCFX_Input_Device::ReadTransferTime(void)
{
return (1536);
}
uint32 PCFX_Input_Device::WriteTransferTime(void)
{
return (1536);
}
uint32 PCFX_Input_Device::Read(void)
{
return (0);
}
void PCFX_Input_Device::Write(uint32 data)
{
}
void PCFX_Input_Device::Power(void)
{
}
void PCFX_Input_Device::Frame(uint32_t data)
{
}
static PCFX_Input_Device *devices[TOTAL_PORTS] = {NULL};
// D0 = TRG, trigger bit
// D1 = MOD, multi-tap clear mode?
// D2 = IOS, data direction. 0 = output, 1 = input
static uint8 TapCounter[PCFX_PORTS];
static uint8 control[PCFX_PORTS];
static bool latched[PCFX_PORTS];
static int32 LatchPending[PCFX_PORTS];
static int InputTypes[TOTAL_PORTS];
static const uint32_t *data_ptr[TOTAL_PORTS];
static uint32 data_latch[TOTAL_PORTS];
void FXINPUT_Init(void)
{
RemakeDevices();
}
#ifdef WANT_DEBUGGER
uint32 FXINPUT_GetRegister(const unsigned int id, char *special, const uint32 special_len)
{
uint32 value = 0xDEADBEEF;
switch (id)
{
case FXINPUT_GSREG_KPCTRL0:
case FXINPUT_GSREG_KPCTRL1:
value = control[id == FXINPUT_GSREG_KPCTRL1];
if (special)
{
trio_snprintf(special, special_len, "Trigger: %d, MOD: %d, IOS: %s", value & 0x1, value & 0x2, (value & 0x4) ? "Input" : "Output");
}
break;
}
return value;
}
void FXINPUT_SetRegister(const unsigned int id, uint32 value)
{
}
#endif
static INLINE int32 min(int32 a, int32 b, int32 c)
{
int32 ret = a;
if (b < ret)
ret = b;
if (c < ret)
ret = c;
return (ret);
}
static INLINE int32 CalcNextEventTS(const v810_timestamp_t timestamp)
{
return (min(LatchPending[0] > 0 ? (timestamp + LatchPending[0]) : PCFX_EVENT_NONONO, LatchPending[1] > 0 ? (timestamp + LatchPending[1]) : PCFX_EVENT_NONONO, PCFX_EVENT_NONONO));
}
static uint32_t Dummy;
static void RemakeDevices(int which)
{
int s = 0;
int e = TOTAL_PORTS;
if (which != -1)
{
s = which;
e = which + 1;
}
for (int i = s; i < e; i++)
{
if (devices[i])
delete devices[i];
devices[i] = NULL;
switch (InputTypes[i])
{
default:
case FXIT_NONE:
devices[i] = new PCFX_Input_Device();
data_ptr[i] = &Dummy;
break;
case FXIT_GAMEPAD:
devices[i] = PCFXINPUT_MakeGamepad();
break;
case FXIT_MOUSE:
devices[i] = PCFXINPUT_MakeMouse(i);
break;
}
}
}
void FXINPUT_SetInput(unsigned port, int type, const uint32_t* ptr)
{
data_ptr[port] = ptr;
InputTypes[port] = type; // FXIT_NONE, FXIT_GAMEPAD, FXIT_MOUSE
RemakeDevices(port);
}
void FXINPUT_SetMultitap(bool port1, bool port2)
{
MultiTapEnabled = port1 | port2 << 1;
}
uint8 FXINPUT_Read8(uint32 A, const v810_timestamp_t timestamp)
{
//printf("Read8: %04x\n", A);
return (FXINPUT_Read16(A & ~1, timestamp) >> ((A & 1) * 8));
}
uint16 FXINPUT_Read16(uint32 A, const v810_timestamp_t timestamp)
{
FXINPUT_Update(timestamp);
uint16 ret = 0;
A &= 0xC2;
//printf("Read: %04x\n", A);
if (A == 0x00 || A == 0x80)
{
int w = (A & 0x80) >> 7;
if (latched[w])
ret = 0x8;
else
ret = 0x0;
}
else
{
int which = (A >> 7) & 1;
ret = data_latch[which] >> ((A & 2) ? 16 : 0);
// Which way is correct? Clear on low reads, or both? Official docs only say low...
if (!(A & 0x2))
latched[which] = FALSE;
}
if (!latched[0] && !latched[1])
PCFXIRQ_Assert(PCFXIRQ_SOURCE_INPUT, FALSE);
return (ret);
}
void FXINPUT_Write16(uint32 A, uint16 V, const v810_timestamp_t timestamp)
{
FXINPUT_Update(timestamp);
//printf("Write16: %04x:%02x, %d\n", A, V, timestamp / 1365);
//PCFXIRQ_Assert(PCFXIRQ_SOURCE_INPUT, FALSE);
//if(V != 7 && V != 5)
//printf("PAD Write16: %04x %04x %d\n", A, V, timestamp);
switch (A & 0xC0)
{
case 0x80:
case 0x00:
{
int w = (A & 0x80) >> 7;
if ((V & 0x1) && !(control[w] & 0x1))
{
//printf("Start: %d\n", w);
if (MultiTapEnabled & (1 << w))
{
if (V & 0x2)
TapCounter[w] = 0;
}
LatchPending[w] = 1536;
PCFX_SetEvent(PCFX_EVENT_PAD, CalcNextEventTS(timestamp));
}
control[w] = V & 0x7;
}
break;
}
}
void FXINPUT_Write8(uint32 A, uint8 V, const v810_timestamp_t timestamp)
{
FXINPUT_Write16(A, V, timestamp);
}
void FXINPUT_Frame(void)
{
for (int i = 0; i < TOTAL_PORTS; i++)
{
devices[i]->Frame(data_ptr[i][0]);
}
}
static v810_timestamp_t lastts;
v810_timestamp_t FXINPUT_Update(const v810_timestamp_t timestamp)
{
int32 run_time = timestamp - lastts;
for (int i = 0; i < 2; i++)
{
if (LatchPending[i] > 0)
{
LatchPending[i] -= run_time;
if (LatchPending[i] <= 0)
{
//printf("Update: %d, %d\n", i, timestamp / 1365);
if (MultiTapEnabled & (1 << i))
{
if (TapCounter[i] >= TAP_PORTS)
data_latch[i] = FX_SIG_TAP << 28;
else
{
data_latch[i] = devices[TapMap[i][TapCounter[i]]]->Read();
}
}
else
{
data_latch[i] = devices[i]->Read();
}
// printf("Moo: %d, %d, %08x\n", i, TapCounter[i], data_latch[i]);
latched[i] = TRUE;
control[i] &= ~1;
PCFXIRQ_Assert(PCFXIRQ_SOURCE_INPUT, TRUE);
if (MultiTapEnabled & (1 << i))
{
if (TapCounter[i] < TAP_PORTS)
{
TapCounter[i]++;
}
}
}
}
}
lastts = timestamp;
return CalcNextEventTS(timestamp);
}
void FXINPUT_ResetTS(int32 ts_base)
{
lastts = ts_base;
}
}

View File

@ -1,82 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* input.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_PCFX_INPUT_H
#define __MDFN_PCFX_INPUT_H
namespace MDFN_IEN_PCFX
{
enum
{
FX_SIG_MOUSE = 0xD,
FX_SIG_TAP = 0xE,
FX_SIG_PAD = 0xF
};
class PCFX_Input_Device
{
public:
// PCFX_Input_Device(int which); // "which" is advisory and only should be used in status messages.
virtual ~PCFX_Input_Device();
virtual uint32 ReadTransferTime(void);
virtual uint32 WriteTransferTime(void);
virtual uint32 Read(void);
virtual void Write(uint32 data);
virtual void Power(void);
virtual void Frame(uint32_t data);
};
void FXINPUT_Init(void) MDFN_COLD;
void FXINPUT_SetInput(unsigned port, int type, const uint32_t* ptr);
void FXINPUT_SetMultitap(bool port1, bool port2);
uint16 FXINPUT_Read16(uint32 A, const v810_timestamp_t timestamp);
uint8 FXINPUT_Read8(uint32 A, const v810_timestamp_t timestamp);
void FXINPUT_Write8(uint32 A, uint8 V, const v810_timestamp_t timestamp);
void FXINPUT_Write16(uint32 A, uint16 V, const v810_timestamp_t timestamp);
void FXINPUT_Frame(void);
v810_timestamp_t FXINPUT_Update(const v810_timestamp_t timestamp);
void FXINPUT_ResetTS(int32 ts_base);
#ifdef WANT_DEBUGGER
enum
{
FXINPUT_GSREG_KPCTRL0 = 0,
FXINPUT_GSREG_KPCTRL1
};
uint32 FXINPUT_GetRegister(const unsigned int id, char *special, const uint32 special_len);
void FXINPUT_SetRegister(const unsigned int id, uint32 value);
#endif
}
#endif

View File

@ -1,80 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* gamepad.cpp:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "../pcfx.h"
#include "../input.h"
#include "gamepad.h"
namespace MDFN_IEN_PCFX
{
class PCFX_Input_Gamepad : public PCFX_Input_Device
{
public:
PCFX_Input_Gamepad()
{
buttons = 0;
}
virtual ~PCFX_Input_Gamepad() override
{
}
virtual uint32 ReadTransferTime(void) override
{
return 1536;
}
virtual uint32 WriteTransferTime(void) override
{
return 1536;
}
virtual uint32 Read(void) override
{
return buttons | FX_SIG_PAD << 28;
}
virtual void Write(uint32 data) override
{
}
virtual void Power(void) override
{
buttons = 0;
}
virtual void Frame(uint32_t data) override
{
buttons = data;
}
private:
// 5....098 7......0
// m mldru rs654321
uint16 buttons;
};
PCFX_Input_Device *PCFXINPUT_MakeGamepad(void)
{
return new PCFX_Input_Gamepad();
}
}

View File

@ -1,30 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* gamepad.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PCFX_INPUT_GAMEPAD_H
#define __PCFX_INPUT_GAMEPAD_H
namespace MDFN_IEN_PCFX
{
PCFX_Input_Device *PCFXINPUT_MakeGamepad(void);
}
#endif

View File

@ -1,88 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* mouse.cpp:
** Copyright (C) 2007-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "../pcfx.h"
#include "../input.h"
#include "mouse.h"
namespace MDFN_IEN_PCFX
{
class PCFX_Input_Mouse : public PCFX_Input_Device
{
public:
PCFX_Input_Mouse(int which)
{
dx = 0;
dy = 0;
button = 0;
}
virtual ~PCFX_Input_Mouse() override
{
}
virtual uint32 ReadTransferTime(void) override
{
return (1536);
}
virtual uint32 WriteTransferTime(void) override
{
return (1536);
}
virtual uint32 Read(void) override
{
return FX_SIG_MOUSE << 28 | button << 16 | dx << 8 | dy;
}
virtual void Write(uint32 data) override
{
}
virtual void Power(void) override
{
button = 0;
dx = 0;
dy = 0;
}
virtual void Frame(uint32_t data) override
{
dx = data;
dy = data >> 8;
button = data >> 16 & 3;
}
private:
int8 dx, dy;
// 76543210
// ......RL
uint8 button;
};
PCFX_Input_Device *PCFXINPUT_MakeMouse(int which)
{
return new PCFX_Input_Mouse(which);
}
}

View File

@ -1,30 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* mouse.h:
** Copyright (C) 2007-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PCFX_INPUT_MOUSE_H
#define __PCFX_INPUT_MOUSE_H
namespace MDFN_IEN_PCFX
{
PCFX_Input_Device *PCFXINPUT_MakeMouse(int which);
}
#endif

View File

@ -1,212 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* interrupt.cpp:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "pcfx.h"
#include "interrupt.h"
namespace MDFN_IEN_PCFX
{
static uint16 InterruptAsserted;
static uint16 InterruptMask;
static uint16 InterruptPriority[2];
static void BuildInterruptCache(void)
{
uint32 iwithmask = InterruptAsserted &~ InterruptMask;
int InterruptCache = -1;
int last_prio = -1;
for(int level = 8; level < 16; level++)
if(iwithmask & (1 << (15 - level)))
{
int tmp_prio;
if(level >= 12)
tmp_prio = (InterruptPriority[0] >> ((15 - level) * 3)) & 0x7;
else
tmp_prio = (InterruptPriority[1] >> ((11 - level) * 3)) & 0x7;
if(tmp_prio >= last_prio)
{
if(tmp_prio == last_prio)
{
FXDBG("Undefined IRQ behavior: %d, %d\n", level, tmp_prio);
}
InterruptCache = 8 + tmp_prio;
last_prio = tmp_prio;
}
}
PCFX_V810.SetInt(InterruptCache);
}
void PCFXIRQ_Assert(int source, bool assert)
{
assert(source >= 0 && source <= 7);
InterruptAsserted &= ~(1 << (7 - source));
if(assert)
InterruptAsserted |= (1 << (7 - source));
BuildInterruptCache();
}
uint16 PCFXIRQ_Read16(uint32 A)
{
uint32 ret = 0x00;
switch(A & 0xC0)
{
case 0x00: ret = InterruptAsserted; break;
case 0x40: ret = InterruptMask; break;
case 0x80: ret = InterruptPriority[0]; break;
case 0xC0: ret = InterruptPriority[1]; break;
}
return(ret);
}
uint8 PCFXIRQ_Read8(uint32 A)
{
return(PCFXIRQ_Read16(A&~1) >> ((A & 1) * 8));
}
void PCFXIRQ_Write16(uint32 A, uint16 V)
{
// printf("IRQ Controller Write: %08x %04x\n", A, V);
switch(A & 0xC0)
{
case 0x00: puts("Address error clear");
break;
case 0x40: InterruptMask = V & 0x7F;
BuildInterruptCache();
break;
case 0x80: if(InterruptMask == 0x7F)
{
InterruptPriority[0] = V & 0xFFF;
BuildInterruptCache();
}
break;
case 0xC0: if(InterruptMask == 0x7F)
{
InterruptPriority[1] = V & 0x1FF;
BuildInterruptCache();
}
break;
}
}
void PCFXIRQ_SetRegister(const unsigned int id, uint32 value)
{
switch(id)
{
case PCFXIRQ_GSREG_IMASK:
InterruptMask = value & 0x7F;
BuildInterruptCache();
break;
case PCFXIRQ_GSREG_IPRIO0:
InterruptPriority[0] = value & 0xFFF;
BuildInterruptCache();
break;
case PCFXIRQ_GSREG_IPRIO1:
InterruptPriority[1] = value & 0x1FF;
BuildInterruptCache();
break;
case PCFXIRQ_GSREG_IPEND:
InterruptAsserted = value;
BuildInterruptCache();
break;
}
}
uint32 PCFXIRQ_GetRegister(const unsigned int id, char *special, const uint32 special_len)
{
uint32 value = 0xDEADBEEF;
switch(id)
{
case PCFXIRQ_GSREG_IMASK:
value = InterruptMask;
if(special)
{
trio_snprintf(special, special_len, "IRQ Allowed; HuC6273: %s, HuC6270-B: %s, HuC6272: %s, HuC6270-A: %s, Pad: %s, Timer: %s, Reset: %s",
(InterruptMask & (1 << 0)) ? "No" : "Yes", (InterruptMask & (1 << 1)) ? "No" : "Yes",
(InterruptMask & (1 << 2)) ? "No" : "Yes", (InterruptMask & (1 << 3)) ? "No" : "Yes",
(InterruptMask & (1 << 4)) ? "No" : "Yes", (InterruptMask & (1 << 6)) ? "No" : "Yes",
(InterruptMask & (1 << 7)) ? "No" : "Yes");
}
break;
case PCFXIRQ_GSREG_IPRIO0:
value = InterruptPriority[0];
if(special)
{
trio_snprintf(special, special_len, "HuC6273: %d, HuC6270-B: %d, HuC6272: %d, HuC6270-A: %d",
(InterruptPriority[0] >> 0) & 0x7, (InterruptPriority[0] >> 3) & 0x7,
(InterruptPriority[0] >> 6) & 0x7, (InterruptPriority[0] >> 9) & 0x7);
}
break;
case PCFXIRQ_GSREG_IPRIO1:
value = InterruptPriority[1];
if(special)
{
trio_snprintf(special, special_len, "Pad: %d, ??: %d, Timer: %d, Reset: %d",
(InterruptPriority[1] >> 0) & 0x7, (InterruptPriority[1] >> 3) & 0x7,
(InterruptPriority[1] >> 6) & 0x7, (InterruptPriority[1] >> 9) & 0x7);
}
break;
case PCFXIRQ_GSREG_IPEND:
value = InterruptAsserted;
if(special)
{
trio_snprintf(special, special_len, "HuC6273: %d, HuC6270-B: %d, HuC6272: %d, HuC6270-A: %d, Pad: %d, ??: %d, Timer: %d, Reset: %d", (int)(bool)(value & 0x01), (int)(bool)(value & 0x02),
(int)(bool)(value & 0x04), (int)(bool)(value & 0x08), (int)(bool)(value & 0x10), (int)(bool)(value & 0x20),
(int)(bool)(value & 0x40), (int)(bool)(value & 0x80));
}
break;
}
return value;
}
void PCFXIRQ_Reset(void)
{
InterruptAsserted = 0;
InterruptMask = 0xFFFF;
InterruptPriority[0] = 0;
InterruptPriority[1] = 0;
BuildInterruptCache();
}
}

View File

@ -1,55 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* interrupt.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PCFX_INTERRUPT_H
#define __PCFX_INTERRUPT_H
namespace MDFN_IEN_PCFX
{
#define PCFXIRQ_SOURCE_TIMER 1
#define PCFXIRQ_SOURCE_EX 2
#define PCFXIRQ_SOURCE_INPUT 3
#define PCFXIRQ_SOURCE_VDCA 4
#define PCFXIRQ_SOURCE_KING 5
#define PCFXIRQ_SOURCE_VDCB 6
#define PCFXIRQ_SOURCE_HUC6273 7
void PCFXIRQ_Assert(int source, bool assert);
void PCFXIRQ_Write16(uint32 A, uint16 V);
uint16 PCFXIRQ_Read16(uint32 A);
uint8 PCFXIRQ_Read8(uint32 A);
void PCFXIRQ_Reset(void) MDFN_COLD;
enum
{
PCFXIRQ_GSREG_IMASK = 0,
PCFXIRQ_GSREG_IPRIO0,
PCFXIRQ_GSREG_IPRIO1,
PCFXIRQ_GSREG_IPEND
};
uint32 PCFXIRQ_GetRegister(const unsigned int id, char *special, const uint32 special_len);
void PCFXIRQ_SetRegister(const unsigned int id, uint32 value);
}
#endif

View File

@ -1,309 +0,0 @@
static uint8 MDFN_FASTCALL port_rbyte(v810_timestamp_t &timestamp, uint32 A)
{
if (A >= 0x000 && A <= 0x0FF)
{
Lagged = false;
if (InputCallback)
InputCallback();
return (FXINPUT_Read8(A, timestamp));
}
else if (A >= 0x100 && A <= 0x1FF) // SOUNDBOX dummy
{
timestamp += 4;
}
else if (A >= 0x200 && A <= 0x2FF) // RAINBOW dummy
{
timestamp += 4;
}
else if (A >= 0x300 && A <= 0x3FF) // FXVCE
{
timestamp += 4;
return (FXVCE_Read16(A));
}
else if (A >= 0x400 && A <= 0x5FF) // 0x400-0x4FF: VDC-A ; 0x500-0x5FF: VDC-B
{
timestamp += 4;
return (fx_vdc_chips[(A >> 8) & 0x1]->Read16((A & 4) >> 2));
}
else if (A >= 0x600 && A <= 0x6FF)
{
timestamp += 4;
return (KING_Read8(timestamp, A));
}
else if (A >= 0x700 && A <= 0x7FF)
{
if (!(A & 1))
{
FXDBG("ExBusReset B Read");
return (ExBusReset);
}
return (0);
}
else if (A >= 0xc00 && A <= 0xCFF) // Backup memory control
{
switch (A & 0xC0)
{
case 0x80:
return (BackupControl);
case 0x00:
return (Last_VDC_AR[0]);
case 0x40:
return (Last_VDC_AR[1]);
}
}
else if (A >= 0xe00 && A <= 0xeff)
{
return (PCFXIRQ_Read8(A));
}
else if (A >= 0xf00 && A <= 0xfff)
{
return (FXTIMER_Read8(A, timestamp));
}
else if ((A & 0x7FFFFFFF) >= 0x500000 && (A & 0x7FFFFFFF) <= 0x52ffff)
{
if (WantHuC6273)
return (HuC6273_Read8(A));
}
else if (FXSCSIROM && A >= 0x780000 && A <= 0x7FFFFF)
{
return (FXSCSIROM[A & 0x7FFFF]);
}
else if (FXSCSIROM && A >= 0x600000 && A <= 0x6FFFFF)
{
return (FXSCSI_CtrlRead(A));
}
FXDBG("Unknown 8-bit port read: %08x", A);
return (0x00);
}
static uint16 MDFN_FASTCALL port_rhword(v810_timestamp_t &timestamp, uint32 A)
{
if (A >= 0x000 && A <= 0x0FF)
{
Lagged = false;
if (InputCallback)
InputCallback();
return (FXINPUT_Read16(A, timestamp));
}
else if (A >= 0x100 && A <= 0x1FF) // SOUNDBOX dummy
{
timestamp += 4;
}
else if (A >= 0x200 && A <= 0x2FF) // RAINBOW dummy
{
timestamp += 4;
}
else if (A >= 0x300 && A <= 0x3FF)
{
timestamp += 4;
return (FXVCE_Read16(A));
}
else if (A >= 0x400 && A <= 0x5FF) // 0x400-0x4FF: VDC-A ; 0x500-0x5FF: VDC-B
{
timestamp += 4;
return (fx_vdc_chips[(A >> 8) & 0x1]->Read16((A & 4) >> 2));
}
else if (A >= 0x600 && A <= 0x6FF)
{
timestamp += 4;
return (KING_Read16(timestamp, A));
}
else if (A >= 0x700 && A <= 0x7FF)
{
FXDBG("ExBusReset H Read");
return (ExBusReset);
}
else if (A >= 0xc00 && A <= 0xCFF) // Backup memory control
{
switch (A & 0xC0)
{
case 0x80:
return (BackupControl);
case 0x00:
return (Last_VDC_AR[0]);
case 0x40:
return (Last_VDC_AR[1]);
}
}
else if (A >= 0xe00 && A <= 0xeff)
{
return (PCFXIRQ_Read16(A));
}
else if (A >= 0xf00 && A <= 0xfff)
{
return (FXTIMER_Read16(A, timestamp));
}
else if ((A & 0x7FFFFFFF) >= 0x500000 && (A & 0x7FFFFFFF) <= 0x52ffff)
{
if (WantHuC6273)
return (HuC6273_Read16(A));
}
else if (FXSCSIROM && A >= 0x780000 && A <= 0x7FFFFF)
{
return MDFN_de16lsb<true>(&FXSCSIROM[A & 0x7FFFF]);
}
else if (FXSCSIROM && A >= 0x600000 && A <= 0x6FFFFF)
{
puts("FXSCSI 16-bit:");
return (FXSCSI_CtrlRead(A));
}
FXDBG("Unknown 16-bit port read: %08x", A);
return (0x00);
}
static void MDFN_FASTCALL port_wbyte(v810_timestamp_t &timestamp, uint32 A, uint8 V)
{
if (A >= 0x000 && A <= 0x0FF)
FXINPUT_Write8(A, V, timestamp);
else if (A >= 0x100 && A <= 0x1FF)
{
timestamp += 2;
SoundBox_Write(A, V, timestamp);
}
else if (A >= 0x200 && A <= 0x2FF)
{
timestamp += 2;
RAINBOW_Write8(A, V);
}
else if (A >= 0x300 && A <= 0x3FF) // FXVCE
{
timestamp += 2;
FXVCE_Write16(A, V);
}
else if (A >= 0x400 && A <= 0x5FF) // 0x400-0x4FF: VDC-A ; 0x500-0x5FF: VDC-B
{
timestamp += 2;
if (!(A & 4))
Last_VDC_AR[(A >> 8) & 0x1] = V;
fx_vdc_chips[(A >> 8) & 0x1]->Write16((A & 4) >> 2, V);
}
else if (A >= 0x600 && A <= 0x6FF)
{
timestamp += 2;
KING_Write8(timestamp, A, V);
}
else if (A >= 0x700 && A <= 0x7FF)
{
if (!(A & 1))
{
FXDBG("ExBusReset B Write: %02x", V & 1);
ExBusReset = V & 1;
}
}
else if (A >= 0xc00 && A <= 0xCFF)
{
switch (A & 0xC1)
{
case 0x80:
BackupControl = V & 0x3;
break;
default:
FXDBG("Port 8-bit write: %08x %02x", A, V);
break;
}
}
else if (A >= 0xe00 && A <= 0xeff)
{
FXDBG("IRQ write8: %08x %02x", A, V);
PCFXIRQ_Write16(A, V);
}
else if ((A & 0x7FFFFFFF) >= 0x500000 && (A & 0x7FFFFFFF) <= 0x52ffff)
{
if (WantHuC6273)
HuC6273_Write16(A, V);
}
else if (FXSCSIROM && A >= 0x600000 && A <= 0x6FFFFF)
{
FXSCSI_CtrlWrite(A, V);
}
else
{
FXDBG("Port 8-bit write: %08x %02x", A, V);
}
}
static void MDFN_FASTCALL port_whword(v810_timestamp_t &timestamp, uint32 A, uint16 V)
{
if (A >= 0x000 && A <= 0x0FF)
FXINPUT_Write16(A, V, timestamp);
else if (A >= 0x100 && A <= 0x1FF)
{
timestamp += 2;
SoundBox_Write(A, V, timestamp);
}
else if (A >= 0x200 && A <= 0x2FF)
{
timestamp += 2;
RAINBOW_Write16(A, V);
}
else if (A >= 0x300 && A <= 0x3FF)
{
timestamp += 2;
FXVCE_Write16(A, V);
}
else if (A >= 0x400 && A <= 0x5FF) // 0x400-0x4FF: VDC-A ; 0x500-0x5FF: VDC-B
{
timestamp += 2;
if (!(A & 4))
Last_VDC_AR[(A >> 8) & 0x1] = V;
fx_vdc_chips[(A >> 8) & 0x1]->Write16((A & 4) >> 2, V);
}
else if (A >= 0x600 && A <= 0x6FF)
{
timestamp += 2;
KING_Write16(timestamp, A, V);
}
else if (A >= 0x700 && A <= 0x7FF)
{
ExBusReset = V & 1;
FXDBG("ExBusReset H Write: %04x", V);
}
else if (A >= 0x800 && A <= 0x8FF) // ?? LIP writes here
{
FXDBG("Port 16-bit write: %08x %04x", A, V);
}
else if (A >= 0xc00 && A <= 0xCFF)
{
switch (A & 0xC0)
{
case 0x80:
BackupControl = V & 0x3;
break;
default:
FXDBG("Port 16-bit write: %08x %04x", A, V);
break;
}
}
else if (A >= 0xe00 && A <= 0xeff)
{
PCFXIRQ_Write16(A, V);
}
else if (A >= 0xF00 && A <= 0xFFF)
{
FXTIMER_Write16(A, V, timestamp);
}
else if ((A & 0x7FFFFFFF) >= 0x500000 && (A & 0x7FFFFFFF) <= 0x52ffff)
{
if (WantHuC6273)
HuC6273_Write16(A, V);
}
else if (FXSCSIROM && A >= 0x600000 && A <= 0x6FFFFF)
{
puts("FXSCSI 16-bit:");
FXSCSI_CtrlWrite(A, V);
}
else
{
FXDBG("Port 16-bit write: %08x %04x", A, V);
}
}

View File

@ -1,284 +0,0 @@
/*
* jrevdct.c
*
* Copyright (C) 1991, 1992, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the basic inverse-DCT transformation subroutine.
*
* This implementation is based on an algorithm described in
* C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
* Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
* Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
* The primary algorithm described there uses 11 multiplies and 29 adds.
* We use their alternate method with 12 multiplies and 32 adds.
* The advantage of this method is that no data path contains more than one
* multiplication; this allows a very simple and accurate implementation in
* scaled fixed-point arithmetic, with a minimal number of shifts.
*/
/* Modified 2007-2016 for usage in Mednafen */
#include "defs.h"
#include "jrevdct.h"
namespace MDFN_IEN_PCFX
{
/*
* This routine is specialized to the case DCTSIZE = 8.
*/
#define DCTSIZE 8
/*
* A 2-D IDCT can be done by 1-D IDCT on each row followed by 1-D IDCT
* on each column. Direct algorithms are also available, but they are
* much more complex and seem not to be any faster when reduced to code.
*
* The poop on this scaling stuff is as follows:
*
* Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
* larger than the true IDCT outputs. The final outputs are therefore
* a factor of N larger than desired; since N=8 this can be cured by
* a simple right shift at the end of the algorithm. The advantage of
* this arrangement is that we save two multiplications per 1-D IDCT,
* because the y0 and y4 inputs need not be divided by sqrt(N).
*
* We have to do addition and subtraction of the integer inputs, which
* is no problem, and multiplication by fractional constants, which is
* a problem to do in integer arithmetic. We multiply all the constants
* by CONST_SCALE and convert them to integer constants (thus retaining
* CONST_BITS bits of precision in the constants). After doing a
* multiplication we have to divide the product by CONST_SCALE, with proper
* rounding, to produce the correct output. This division can be done
* cheaply as a right shift of CONST_BITS bits. We postpone shifting
* as long as possible so that partial sums can be added together with
* full fractional precision.
*
* The outputs of the first pass are scaled up by PASS1_BITS bits so that
* they are represented to better-than-integral precision. These outputs
* require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
* with the recommended scaling. (To scale up 12-bit sample data further, an
* intermediate int32 array would be needed.)
*
* To avoid overflow of the 32-bit intermediate results in pass 2, we must
* have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
* shows that the values given below are the most effective.
*/
#define CONST_BITS 13
#define PASS1_BITS 2
#if ((8 + CONST_BITS + PASS1_BITS) > 26)
#error "Too many bits1!"
#endif
#define ONE ((int32) 1)
#define CONST_SCALE (ONE << CONST_BITS)
/* Convert a positive real constant to an integer scaled by CONST_SCALE. */
#define FIX(x) ((int32) ((x) * CONST_SCALE + 0.5))
/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
* causing a lot of useless floating-point operations at run time.
* To get around this we use the following pre-calculated constants.
* If you change CONST_BITS you may want to add appropriate values.
* (With a reasonable C compiler, you can just rely on the FIX() macro...)
*/
#if CONST_BITS == 13
#define FIX_0_298631336 ((int32) 2446) /* FIX(0.298631336) */
#define FIX_0_390180644 ((int32) 3196) /* FIX(0.390180644) */
#define FIX_0_541196100 ((int32) 4433) /* FIX(0.541196100) */
#define FIX_0_765366865 ((int32) 6270) /* FIX(0.765366865) */
#define FIX_0_899976223 ((int32) 7373) /* FIX(0.899976223) */
#define FIX_1_175875602 ((int32) 9633) /* FIX(1.175875602) */
#define FIX_1_501321110 ((int32) 12299) /* FIX(1.501321110) */
#define FIX_1_847759065 ((int32) 15137) /* FIX(1.847759065) */
#define FIX_1_961570560 ((int32) 16069) /* FIX(1.961570560) */
#define FIX_2_053119869 ((int32) 16819) /* FIX(2.053119869) */
#define FIX_2_562915447 ((int32) 20995) /* FIX(2.562915447) */
#define FIX_3_072711026 ((int32) 25172) /* FIX(3.072711026) */
#else
#define FIX_0_298631336 FIX(0.298631336)
#define FIX_0_390180644 FIX(0.390180644)
#define FIX_0_541196100 FIX(0.541196100)
#define FIX_0_765366865 FIX(0.765366865)
#define FIX_0_899976223 FIX(0.899976223)
#define FIX_1_175875602 FIX(1.175875602)
#define FIX_1_501321110 FIX(1.501321110)
#define FIX_1_847759065 FIX(1.847759065)
#define FIX_1_961570560 FIX(1.961570560)
#define FIX_2_053119869 FIX(2.053119869)
#define FIX_2_562915447 FIX(2.562915447)
#define FIX_3_072711026 FIX(3.072711026)
#endif
/* Descale and correctly round an int32 value that's scaled by N bits.
* We assume RIGHT_SHIFT rounds towards minus infinity, so adding
* the fudge factor is correct for either sign of X.
*/
#define RIGHT_SHIFT(x,shft) ((x) >> (shft))
#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
#define MULTIPLY(var,const) ((var) * (const))
/*
* Perform the inverse DCT on one block of coefficients.
*/
void j_rev_dct(DCTBLOCK data)
{
int32 tmp0, tmp1, tmp2, tmp3;
int32 tmp10, tmp11, tmp12, tmp13;
int32 z1, z2, z3, z4, z5;
register DCTELEM *dataptr;
int rowctr;
/* Pass 1: process rows. */
/* Note results are scaled up by sqrt(8) compared to a true IDCT; */
/* furthermore, we scale the results by 2**PASS1_BITS. */
dataptr = data;
for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--)
{
/* Even part: reverse the even part of the forward DCT. */
/* The rotator is sqrt(2)*c(-6). */
z2 = (int32) dataptr[2];
z3 = (int32) dataptr[6];
z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
tmp0 = ((uint32) dataptr[0] + (uint32) dataptr[4]) << CONST_BITS;
tmp1 = ((uint32) dataptr[0] - (uint32) dataptr[4]) << CONST_BITS;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
/* Odd part per figure 8; the matrix is unitary and hence its
* transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
*/
tmp0 = (int32) dataptr[7];
tmp1 = (int32) dataptr[5];
tmp2 = (int32) dataptr[3];
tmp3 = (int32) dataptr[1];
z1 = tmp0 + tmp3;
z2 = tmp1 + tmp2;
z3 = tmp0 + tmp2;
z4 = tmp1 + tmp3;
z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
z3 += z5;
z4 += z5;
tmp0 += z1 + z3;
tmp1 += z2 + z4;
tmp2 += z2 + z3;
tmp3 += z1 + z4;
/* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
dataptr += DCTSIZE; /* advance pointer to next row */
}
/* Pass 2: process columns. */
/* Note that we must descale the results by a factor of 8 == 2**3, */
/* and also undo the PASS1_BITS scaling. */
dataptr = data;
for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
/* Even part: reverse the even part of the forward DCT. */
/* The rotator is sqrt(2)*c(-6). */
z2 = (int32) dataptr[DCTSIZE*2];
z3 = (int32) dataptr[DCTSIZE*6];
z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
tmp0 = ((uint32) dataptr[DCTSIZE*0] + (uint32) dataptr[DCTSIZE*4]) << CONST_BITS;
tmp1 = ((uint32) dataptr[DCTSIZE*0] - (uint32) dataptr[DCTSIZE*4]) << CONST_BITS;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
/* Odd part per figure 8; the matrix is unitary and hence its
* transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
*/
tmp0 = (int32) dataptr[DCTSIZE*7];
tmp1 = (int32) dataptr[DCTSIZE*5];
tmp2 = (int32) dataptr[DCTSIZE*3];
tmp3 = (int32) dataptr[DCTSIZE*1];
z1 = tmp0 + tmp3;
z2 = tmp1 + tmp2;
z3 = tmp0 + tmp2;
z4 = tmp1 + tmp3;
z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
z3 += z5;
z4 += z5;
tmp0 += z1 + z3;
tmp1 += z2 + z4;
tmp2 += z2 + z3;
tmp3 += z1 + z4;
/* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS+PASS1_BITS+1);
dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS+PASS1_BITS+1);
dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS+PASS1_BITS+1);
dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS+PASS1_BITS+1);
dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS+PASS1_BITS+1);
dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS+PASS1_BITS+1);
dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS+PASS1_BITS+1);
dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS+PASS1_BITS+1);
dataptr++; /* advance pointer to next column */
}
}
}

View File

@ -1,14 +0,0 @@
#ifndef __MDFN_PCFX_JREVDCT_H
#define __MDFN_PCFX_JREVDCT_H
namespace MDFN_IEN_PCFX
{
typedef int32* DCTBLOCK;
typedef int32 DCTELEM;
void j_rev_dct(DCTBLOCK data);
}
#endif

View File

@ -1,124 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* king-bgfast-blit.inc:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
switch(bgmode & 0x7)
{
case 0x01: // 4 color, 1/4 byte per pixel :b
sexy_y_pos >>= 3;
for(int x = 0; x < 256 + 8; x+= 8)
{
DRAWBG8x1_LPRE();
const uint16 *cgptr;
uint32 pbn = 0;
if(BGFAST_BATMODE)
{
uint16 bat = king_bat_base[(bat_offset + (bat_x + bat_y)) & 0x1FFFF];
pbn = (bat >> 12) << 2;
bat &= 0x0FFF;
cgptr = &king_cg_base[(cg_offset + (bat * 8) + ysmall) & 0x1FFFF];
}
else
cgptr = &king_cg_base[(cg_offset + (bat_x * 1) + sexy_y_pos) & 0x1FFFF];
DRAWBG8x1_4(target + x, cgptr, palette_ptr + pbn, layer_or);
DRAWBG8x1_LPOST();
}
break;
case 0x02: // 16 color, 1/2 byte per pixel
sexy_y_pos >>= 2;
for(int x = 0; x < 256 + 8; x+= 8)
{
DRAWBG8x1_LPRE();
const uint16 *cgptr;
uint32 pbn = 0;
if(BGFAST_BATMODE)
{
uint16 bat = king_bat_base[(bat_offset + (bat_x + bat_y)) & 0x1FFFF];
pbn = ((bat >> 12) << 4);
bat &= 0x0FFF;
cgptr = &king_cg_base[(cg_offset + (bat * 16) + ysmall * 2) & 0x1FFFF];
}
else
cgptr = &king_cg_base[(cg_offset + (bat_x * 2) + sexy_y_pos) & 0x1FFFF];
DRAWBG8x1_16(target + x, cgptr, palette_ptr + pbn, layer_or);
DRAWBG8x1_LPOST();
}
break;
case 0x03: // 256 color, 1 byte per pixel palettized - OK
sexy_y_pos >>= 1;
for(int x = 0; x < 256 + 8; x+= 8)
{
DRAWBG8x1_LPRE();
const uint16 *cgptr;
if(BGFAST_BATMODE)
{
uint16 bat = king_bat_base[(bat_offset + (bat_x + bat_y)) & 0x1FFFF];
cgptr = &king_cg_base[(cg_offset + (bat * 32) + ysmall * 4) & 0x1FFFF];
}
else
cgptr = &king_cg_base[(cg_offset + (bat_x * 4) + sexy_y_pos) & 0x1FFFF];
DRAWBG8x1_256(target + x, cgptr, palette_ptr, layer_or);
DRAWBG8x1_LPOST();
}
break;
case 0x04: // 64K color, 2 bytes per pixel - OK
for(int x = 0; x < 256 + 8; x+=8)
{
DRAWBG8x1_LPRE();
const uint16 *cgptr;
if(BGFAST_BATMODE)
{
uint16 bat = king_bat_base[(bat_offset + (bat_x + bat_y)) & 0x1FFFF];
cgptr = &king_cg_base[(cg_offset + (bat * 64) + ysmall * 8) & 0x1FFFF];
}
else
cgptr = &king_cg_base[(cg_offset + (bat_x * 8) + sexy_y_pos) & 0x1FFFF];
DRAWBG8x1_64K(target + x, cgptr, palette_ptr, layer_or);
DRAWBG8x1_LPOST();
}
break;
case 0x05: // 16M color, 2 bytes per pixel - OK
for(int x = 0; x < 256 + 8; x+=8)
{
DRAWBG8x1_LPRE();
const uint16 *cgptr;
if(BGFAST_BATMODE)
{
uint16 bat = king_bat_base[(bat_offset + (bat_x + bat_y)) & 0x1FFFF];
cgptr = &king_cg_base[(cg_offset + (bat * 64) + ysmall * 8) & 0x1FFFF];
}
else
cgptr = &king_cg_base[(cg_offset + (bat_x * 8) + sexy_y_pos) & 0x1FFFF];
DRAWBG8x1_16M(target + x, cgptr, palette_ptr, layer_or);
DRAWBG8x1_LPOST();
}
break;
}

View File

@ -1,270 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* king-bgfast.inc:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// Loop prefix non-endless
#define DRAWBG8x1_LPRE() if(bat_x < bat_width) {
// Loop postfix non-endless
#define DRAWBG8x1_LPOST() } bat_x = (bat_x + 1) & bat_width_mask;
#define CDBG_REASON(format, ...)
//printf("BG%d Reason: " format "\n", n, ## __VA_ARGS__);
static bool CanDrawBG_Fast(int n)
{
static const int cg_per_mode[0x8] =
{
0, // Invalid mode
1, // 2-bit mode
2, // 4-bit mode
4, // 8-bit mode
8, // 16-bit mode
8, // 16-bit mode
8, // 16-bit mode
8, // 16-bit mode
};
const unsigned int bgmode = (king->bgmode >> (n * 4)) & 0xF;
const uint32 bat_offset = king->BGBATAddr[n] * 1024;
const uint32 cg_offset = king->BGCGAddr[n] * 1024;
const uint32 bg_width = (king->BGSize[n] & 0xF0) >> 4;
const uint32 bg_height = king->BGSize[n] & 0x0F;
// If the bgmode is 0, or 6/7(EXT DOT modes), abort.
if(!(bgmode & 0x7) || ((bgmode & 0x7) >= 6))
{
CDBG_REASON("Mode %02x out of range", bgmode);
return(FALSE);
}
// BG width out of range?
if(bg_width < 0x3 || bg_width > 0xA)
{
CDBG_REASON("Width %02x out of range", bg_width);
return(FALSE);
}
// BG height out of range?
if(bg_height < 0x3 || bg_height > 0xA)
{
CDBG_REASON("Height %02x out of range", bg_height);
return(FALSE);
}
// Time for very stringent checks for BG0! Don't draw if the sub-screen is a different size than the main screen,
// or the subscreen CG base != the main screen CG base, or the subscreen BAT base != main screen BAT base(when bgmode & 0x8 is TRUE)
if(!n)
{
if(king->priority & 0x1000)
{
CDBG_REASON("Affine transform enabled");
return(FALSE);
}
if((king->BGSize[0] & 0xFF) != (king->BGSize[0] >> 8))
{
CDBG_REASON("Main Screen/Sub Screen Size Mismatch");
return(FALSE);
}
// Since we already made sure the main screen/sub screen sizes match, we only
// care if BG base or CG base don't match if endless/repeat scrolling is enabled.
// Otherwise, the subscreen won't show at all.
if(king->BGScrollMode & 0x1)
{
if(king->BGCGAddr[0] != king->BG0SubCGAddr)
{
CDBG_REASON("Main Screen/Sub Screen CG base mismatch");
return(FALSE);
}
if(bgmode & 0x8)
{
if(king->BGBATAddr[0] != king->BG0SubBATAddr)
{
CDBG_REASON("Main Screen/Sub Screen BAT base mismatch");
return(FALSE);
}
}
}
}
// If microprogram fetching is disabled, abort.
if(!(king->MPROGControl & 0x1))
{
CDBG_REASON("Microprogram disabled");
return(FALSE);
}
else
{
int remap_thing = 0;
bool bat_fetch = FALSE;
for(int x = 0; x < 16; x++)
{
uint16 mpd;
// Forcing CG and BAT to 0 if the affine bit != rotate_mode is not technically correct.
// If there is a mismatch, it's more likely the effective CG and BAT address for the pixel/segment
// being drawn won't be calculated correctly, likely being just the initial offsets.
mpd = king->MPROGData[x];
// Fetching for this BG number?
if(((mpd >> 6) & 0x3) != n)
continue;
// NOP
if(mpd & 0x100)
continue;
// Affine bit.
if(mpd & 0x20)
{
CDBG_REASON("Affine bit set");
return(FALSE);
}
// BAT fetch
if(mpd & 0x10)
{
if(((bat_offset & 0x20000) >> 14) != (x & 8))
{
CDBG_REASON("BAT MPROG/base bank mismatch");
return(FALSE);
}
bat_fetch = TRUE;
}
else // CG fetch:
{
// CG offset/bank mismatch...
if(((cg_offset & 0x20000) >> 14) != (x & 8))
{
CDBG_REASON("CG MPROG/base bank mismatch");
return(FALSE);
}
// Mismatch between CG fetch type and BG mode!
if((mpd & 0x8) != (bgmode & 0x8))
{
CDBG_REASON("Mismatch between CG fetch type and bg mode");
return(FALSE);
}
// Skewed CG fetch order
if((mpd & 0x7) != remap_thing)
{
CDBG_REASON("Skewed CG fetch order");
return(FALSE);
}
remap_thing++;
}
}
// CG fetch count mismatch
if(remap_thing != cg_per_mode[bgmode & 0x7])
{
CDBG_REASON("CG fetch count mismatch");
return(FALSE);
}
// BG mode demands a BAT fetch, but we don't have one!
if((bgmode & 0x8) && !bat_fetch)
{
CDBG_REASON("Missing BAT fetch");
return(FALSE);
}
}
return(TRUE);
}
static void DrawBG_Fast(uint32 *target, int n)
{
const uint16 bgmode = (king->bgmode >> (n * 4)) & 0xF;
const bool endless = (king->BGScrollMode >> n) & 0x1;
const uint32 XScroll = sign_x_to_s32((n ? 10 : 11), king->BGXScroll[n]);
const uint32 YScroll = sign_x_to_s32((n ? 10 : 11), king->BGYScroll[n]);
const uint32 bat_offset = king->BGBATAddr[n] * 1024;
const uint32 cg_offset = king->BGCGAddr[n] * 1024;
const uint32 bat_and_cg_page = (king->PageSetting & 0x0010) ? 1 : 0;
const uint32 YOffset = (YScroll + (fx_vce.raster_counter - 22)) & 0xFFFF;
const uint32 layer_or = (LAYER_BG0 + n) << 28;
const int ysmall = YOffset & 0x7;
const unsigned int bat_width_shift = (king->BGSize[n] & 0xF0) >> 4;
const unsigned int bat_width = (1 << bat_width_shift) >> 3;
const unsigned int bat_width_mask = endless ? (bat_width - 1) : ((((1 << 0xA) * 2) / 8) - 1);
const int bat_height_shift = king->BGSize[n] & 0x0F;
const int bat_height = (1 << bat_height_shift) >> 3;
const int bat_height_mask = endless ? (bat_height - 1) : ((((1 << 0xA) * 2) / 8) - 1);
// We don't need to &= cg_offset and bat_offset with 0x1ffff after here, as the effective addresses
// calculated with them are anded with 0x1ffff in the rendering code already.
const uint16 * const king_cg_base = &king->KRAM[bat_and_cg_page][cg_offset & 0x20000];
const uint16 * const king_bat_base = &king->KRAM[bat_and_cg_page][bat_offset & 0x20000];
int bat_y = (YOffset >> 3) & bat_height_mask;
uint32 bat_x = (XScroll >> 3) & bat_width_mask;
target += 8 - (XScroll & 0x7);
// If we're in non-endless scroll mode, and we've scrolled past our visible area in the vertical direction, so return.
if(!endless && bat_y >= bat_height) // Draw this line as transparency and return?
{
return;
}
// Adjust/corrupt bat_y to be faster in our blitting code
bat_y = (bat_y << bat_width_shift) >> 3;
const uint32 palette_offset = ((vce_rendercache.palette_offset[1 + (n >> 1)] >> ((n & 1) ? 8 : 0)) << 1) & 0x1FF;
const uint32 * const palette_ptr = &vce_rendercache.palette_table_cache[palette_offset];
{
int wmul = (1 << bat_width_shift), wmask = (1 << bat_height_shift) - 1;
int sexy_y_pos = (YOffset & wmask) * wmul;
#if 0
#define BGFAST_BATMODE (bgmode & 0x8)
#include "king-bgfast-blit.inc"
#else
if(bgmode & 0x8)
{
#define BGFAST_BATMODE 1
#include "king-bgfast-blit.inc"
#undef BGFAST_BATMODE
}
else
{
#define BGFAST_BATMODE 0
#include "king-bgfast-blit.inc"
#undef BGFAST_BATMODE
}
#endif
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,212 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* king.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PCFX_KING_H
#define __PCFX_KING_H
namespace MDFN_IEN_PCFX
{
//
// Be sure to keep the numbered/lettered *_GSREG_* registers(MPROG0*, AFFIN*, etc.) here in contiguous sequential order(since we do stuff like "- KING_GSREG_MPROG0"
// in king.cpp.
//
void KING_StartFrame(VDC **, EmulateSpecStruct *espec);
void KING_SetPixelFormat();
uint16 FXVCE_Read16(uint32 A);
void FXVCE_Write16(uint32 A, uint16 V);
#ifdef WANT_DEBUGGER
enum
{
FXVCE_GSREG_Line = 0,
FXVCE_GSREG_PRIO0,
FXVCE_GSREG_PRIO1,
FXVCE_GSREG_PICMODE,
FXVCE_GSREG_PALRWOF,
FXVCE_GSREG_PALRWLA,
FXVCE_GSREG_PALOFS0,
FXVCE_GSREG_PALOFS1,
FXVCE_GSREG_PALOFS2,
FXVCE_GSREG_PALOFS3,
FXVCE_GSREG_CCR,
FXVCE_GSREG_BLE,
FXVCE_GSREG_SPBL,
FXVCE_GSREG_COEFF0,
FXVCE_GSREG_COEFF1,
FXVCE_GSREG_COEFF2,
FXVCE_GSREG_COEFF3,
FXVCE_GSREG_COEFF4,
FXVCE_GSREG_COEFF5,
FXVCE_GSREG_CKeyY,
FXVCE_GSREG_CKeyU,
FXVCE_GSREG_CKeyV
};
uint32 FXVCE_GetRegister(const unsigned int id, char* special, const uint32 special_len);
void FXVCE_SetRegister(const unsigned int id, uint32 value);
#endif
uint8 KING_Read8(const v810_timestamp_t timestamp, uint32 A);
uint16 KING_Read16(const v810_timestamp_t timestamp, uint32 A);
void KING_Write8(const v810_timestamp_t timestamp, uint32 A, uint8 V);
void KING_Write16(const v810_timestamp_t timestamp, uint32 A, uint16 V);
void KING_Init(void) MDFN_COLD;
void KING_Reset(const v810_timestamp_t timestamp) MDFN_COLD;
uint16 KING_GetADPCMHalfWord(int ch);
uint8 KING_MemPeek(uint32 A);
uint8 KING_RB_Fetch();
void KING_SetLayerEnableMask(uint64 mask);
#ifdef WANT_DEBUGGER
enum
{
KING_GSREG_AR = 0,
KING_GSREG_MPROGADDR,
KING_GSREG_MPROGCTRL,
KING_GSREG_PAGESET,
KING_GSREG_RTCTRL,
KING_GSREG_RKRAMA,
KING_GSREG_RSTART,
KING_GSREG_RCOUNT,
KING_GSREG_RIRQLINE,
KING_GSREG_KRAMWA,
KING_GSREG_KRAMRA,
KING_GSREG_DMATA,
KING_GSREG_DMATS,
KING_GSREG_DMASTT,
KING_GSREG_ADPCMCTRL,
KING_GSREG_ADPCMBM0,
KING_GSREG_ADPCMBM1,
KING_GSREG_ADPCMPA0,
KING_GSREG_ADPCMPA1,
KING_GSREG_ADPCMSA0,
KING_GSREG_ADPCMSA1,
KING_GSREG_ADPCMIA0,
KING_GSREG_ADPCMIA1,
KING_GSREG_ADPCMEA0,
KING_GSREG_ADPCMEA1,
KING_GSREG_ADPCMStat,
KING_GSREG_Reg01,
KING_GSREG_Reg02,
KING_GSREG_Reg03,
KING_GSREG_SUBCC,
KING_GSREG_DB,
KING_GSREG_BSY,
KING_GSREG_REQ,
KING_GSREG_ACK,
KING_GSREG_MSG,
KING_GSREG_IO,
KING_GSREG_CD,
KING_GSREG_SEL,
KING_GSREG_BGMODE,
KING_GSREG_BGPRIO,
KING_GSREG_BGSCRM,
KING_GSREG_BGSIZ0,
KING_GSREG_BGSIZ1,
KING_GSREG_BGSIZ2,
KING_GSREG_BGSIZ3,
KING_GSREG_BGXSC0,
KING_GSREG_BGXSC1,
KING_GSREG_BGXSC2,
KING_GSREG_BGXSC3,
KING_GSREG_BGYSC0,
KING_GSREG_BGYSC1,
KING_GSREG_BGYSC2,
KING_GSREG_BGYSC3,
KING_GSREG_BGBATS,
KING_GSREG_BGBAT0,
KING_GSREG_BGBAT1,
KING_GSREG_BGBAT2,
KING_GSREG_BGBAT3,
KING_GSREG_BGCGS,
KING_GSREG_BGCG0,
KING_GSREG_BGCG1,
KING_GSREG_BGCG2,
KING_GSREG_BGCG3,
KING_GSREG_AFFINA,
KING_GSREG_AFFINB,
KING_GSREG_AFFINC,
KING_GSREG_AFFIND,
KING_GSREG_AFFINX,
KING_GSREG_AFFINY,
KING_GSREG_MPROG0,
KING_GSREG_MPROG1,
KING_GSREG_MPROG2,
KING_GSREG_MPROG3,
KING_GSREG_MPROG4,
KING_GSREG_MPROG5,
KING_GSREG_MPROG6,
KING_GSREG_MPROG7,
KING_GSREG_MPROG8,
KING_GSREG_MPROG9,
KING_GSREG_MPROGA,
KING_GSREG_MPROGB,
KING_GSREG_MPROGC,
KING_GSREG_MPROGD,
KING_GSREG_MPROGE,
KING_GSREG_MPROGF
};
uint32 KING_GetRegister(const unsigned int id, char* special, const uint32 special_len);
void KING_SetRegister(const unsigned int id, uint32 value);
#endif
void KING_NotifyOfBPE(bool read, bool write);
void KING_SetLogFunc(void (*logfunc)(const char *, const char *, ...));
void KING_EndFrame(v810_timestamp_t timestamp);
void KING_ResetTS(v810_timestamp_t ts_base);
v810_timestamp_t MDFN_FASTCALL KING_Update(const v810_timestamp_t timestamp);
}
#endif

View File

@ -1,83 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* king_mix_body.inc:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
if(fx_vce.dot_clock) // No cellophane in 7.16MHz pixel mode
{
if(HighDotClockWidth == 341)
for(unsigned int x = 0; x < 341; x++)
{
LAYER_MIX_BODY(x * 256 / 341, x);
LAYER_MIX_FINAL_NOCELLO;
}
else if(HighDotClockWidth == 256)
for(unsigned int x = 0; x < 256; x++)
{
LAYER_MIX_BODY(x, x * 341 / 256);
LAYER_MIX_FINAL_NOCELLO;
}
else
for(unsigned int x = 0; x < 1024; x++)
{
LAYER_MIX_BODY(x / 4, x / 3);
LAYER_MIX_FINAL_NOCELLO;
}
}
else if((vce_rendercache.BLE & 0xC000) == 0xC000) // Front cellophane
{
uint8 CCR_Y_front = vce_rendercache.coefficient_mul_table_y[(vce_rendercache.coefficients[0] >> 8) & 0xF][(vce_rendercache.CCR >> 8) & 0xFF];
int8 CCR_U_front = vce_rendercache.coefficient_mul_table_uv[(vce_rendercache.coefficients[0] >> 4) & 0xF][(vce_rendercache.CCR & 0xF0)];
int8 CCR_V_front = vce_rendercache.coefficient_mul_table_uv[(vce_rendercache.coefficients[0] >> 0) & 0xF][(vce_rendercache.CCR << 4) & 0xF0];
BPC_Cache = 0x008080 | (LAYER_NONE << 28);
for(unsigned int x = 0; x < 256; x++)
{
LAYER_MIX_BODY(x, x);
LAYER_MIX_FINAL_FRONT_CELLO;
}
}
else if((vce_rendercache.BLE & 0xC000) == 0x4000) // Back cellophane
{
BPC_Cache = ((vce_rendercache.CCR & 0xFF00) << 8) | ((vce_rendercache.CCR & 0xF0) << 8) | ((vce_rendercache.CCR & 0x0F) << 4) | (LAYER_NONE << 28);
for(unsigned int x = 0; x < 256; x++)
{
LAYER_MIX_BODY(x, x);
LAYER_MIX_FINAL_BACK_CELLO;
}
}
else if(ble_cache_any) // No front/back cello, but cellophane on at least 1 layer
{
for(unsigned int x = 0; x < 256; x++)
{
LAYER_MIX_BODY(x, x);
LAYER_MIX_FINAL_CELLO
}
}
else // No cellophane at all
{
for(unsigned int x = 0; x < 256; x++)
{
LAYER_MIX_BODY(x, x);
LAYER_MIX_FINAL_NOCELLO
}
}

View File

@ -1,278 +0,0 @@
/******************************************************************************/
/* Mednafen - Multi-system Emulator */
/******************************************************************************/
/* math_ops.h:
** Copyright (C) 2007-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
** Some ideas from:
** blargg
** http://graphics.stanford.edu/~seander/bithacks.html
*/
#ifndef __MDFN_MATH_OPS_H
#define __MDFN_MATH_OPS_H
#if defined(_MSC_VER)
#include <intrin.h>
#endif
static INLINE unsigned MDFN_lzcount16_0UD(uint16 v)
{
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
return 15 ^ 31 ^ __builtin_clz(v);
#elif defined(_MSC_VER)
unsigned long idx;
_BitScanReverse(&idx, v);
return 15 ^ idx;
#else
unsigned ret = 0;
unsigned tmp;
tmp = !(v & 0xFF00) << 3; v <<= tmp; ret += tmp;
tmp = !(v & 0xF000) << 2; v <<= tmp; ret += tmp;
tmp = !(v & 0xC000) << 1; v <<= tmp; ret += tmp;
tmp = !(v & 0x8000) << 0; ret += tmp;
return(ret);
#endif
}
static INLINE unsigned MDFN_lzcount32_0UD(uint32 v)
{
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
return __builtin_clz(v);
#elif defined(_MSC_VER)
unsigned long idx;
_BitScanReverse(&idx, v);
return 31 ^ idx;
#else
unsigned ret = 0;
unsigned tmp;
tmp = !(v & 0xFFFF0000) << 4; v <<= tmp; ret += tmp;
tmp = !(v & 0xFF000000) << 3; v <<= tmp; ret += tmp;
tmp = !(v & 0xF0000000) << 2; v <<= tmp; ret += tmp;
tmp = !(v & 0xC0000000) << 1; v <<= tmp; ret += tmp;
tmp = !(v & 0x80000000) << 0; ret += tmp;
return(ret);
#endif
}
static INLINE unsigned MDFN_lzcount64_0UD(uint64 v)
{
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
return __builtin_clzll(v);
#elif defined(_MSC_VER)
#if defined(_WIN64)
unsigned long idx;
_BitScanReverse64(&idx, v);
return 63 ^ idx;
#else
unsigned long idx0;
unsigned long idx1;
_BitScanReverse(&idx1, v >> 0);
idx1 -= 32;
if(!_BitScanReverse(&idx0, v >> 32))
idx0 = idx1;
idx0 += 32;
return 63 ^ idx0;
#endif
#else
unsigned ret = 0;
unsigned tmp;
tmp = !(v & 0xFFFFFFFF00000000ULL) << 5; v <<= tmp; ret += tmp;
tmp = !(v & 0xFFFF000000000000ULL) << 4; v <<= tmp; ret += tmp;
tmp = !(v & 0xFF00000000000000ULL) << 3; v <<= tmp; ret += tmp;
tmp = !(v & 0xF000000000000000ULL) << 2; v <<= tmp; ret += tmp;
tmp = !(v & 0xC000000000000000ULL) << 1; v <<= tmp; ret += tmp;
tmp = !(v & 0x8000000000000000ULL) << 0; ret += tmp;
return(ret);
#endif
}
static INLINE unsigned MDFN_tzcount16_0UD(uint16 v)
{
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
return __builtin_ctz(v);
#elif defined(_MSC_VER)
unsigned long idx;
_BitScanForward(&idx, v);
return idx;
#else
unsigned ret = 0;
unsigned tmp;
tmp = !( (uint8)v) << 3; v >>= tmp; ret += tmp;
tmp = !(v & 0x000F) << 2; v >>= tmp; ret += tmp;
tmp = !(v & 0x0003) << 1; v >>= tmp; ret += tmp;
tmp = !(v & 0x0001) << 0; ret += tmp;
return ret;
#endif
}
static INLINE unsigned MDFN_tzcount32_0UD(uint32 v)
{
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
return __builtin_ctz(v);
#elif defined(_MSC_VER)
unsigned long idx;
_BitScanForward(&idx, v);
return idx;
#else
unsigned ret = 0;
unsigned tmp;
tmp = !((uint16)v) << 4; v >>= tmp; ret += tmp;
tmp = !( (uint8)v) << 3; v >>= tmp; ret += tmp;
tmp = !(v & 0x000F) << 2; v >>= tmp; ret += tmp;
tmp = !(v & 0x0003) << 1; v >>= tmp; ret += tmp;
tmp = !(v & 0x0001) << 0; ret += tmp;
return ret;
#endif
}
static INLINE unsigned MDFN_tzcount64_0UD(uint64 v)
{
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
return __builtin_ctzll(v);
#elif defined(_MSC_VER)
#if defined(_WIN64)
unsigned long idx;
_BitScanForward64(&idx, v);
return idx;
#else
unsigned long idx0, idx1;
_BitScanForward(&idx1, v >> 32);
idx1 += 32;
if(!_BitScanForward(&idx0, v))
idx0 = idx1;
return idx0;
#endif
#else
unsigned ret = 0;
unsigned tmp;
tmp = !((uint32)v) << 5; v >>= tmp; ret += tmp;
tmp = !((uint16)v) << 4; v >>= tmp; ret += tmp;
tmp = !( (uint8)v) << 3; v >>= tmp; ret += tmp;
tmp = !(v & 0x000F) << 2; v >>= tmp; ret += tmp;
tmp = !(v & 0x0003) << 1; v >>= tmp; ret += tmp;
tmp = !(v & 0x0001) << 0; ret += tmp;
return ret;
#endif
}
//
// Result is defined for all possible inputs(including 0).
//
static INLINE unsigned MDFN_lzcount16(uint16 v) { return !v ? 16 : MDFN_lzcount16_0UD(v); }
static INLINE unsigned MDFN_lzcount32(uint32 v) { return !v ? 32 : MDFN_lzcount32_0UD(v); }
static INLINE unsigned MDFN_lzcount64(uint64 v) { return !v ? 64 : MDFN_lzcount64_0UD(v); }
static INLINE unsigned MDFN_tzcount16(uint16 v) { return !v ? 16 : MDFN_tzcount16_0UD(v); }
static INLINE unsigned MDFN_tzcount32(uint32 v) { return !v ? 32 : MDFN_tzcount32_0UD(v); }
static INLINE unsigned MDFN_tzcount64(uint64 v) { return !v ? 64 : MDFN_tzcount64_0UD(v); }
static INLINE unsigned MDFN_log2(uint32 v) { return 31 ^ MDFN_lzcount32_0UD(v | 1); }
static INLINE unsigned MDFN_log2(uint64 v) { return 63 ^ MDFN_lzcount64_0UD(v | 1); }
static INLINE unsigned MDFN_log2(int32 v) { return MDFN_log2((uint32)v); }
static INLINE unsigned MDFN_log2(int64 v) { return MDFN_log2((uint64)v); }
// Rounds up to the nearest power of 2(treats input as unsigned to a degree, but be aware of integer promotion rules).
// Returns 0 on overflow.
static INLINE uint64 round_up_pow2(uint32 v) { uint64 tmp = (uint64)1 << MDFN_log2(v); return tmp << (tmp < v); }
static INLINE uint64 round_up_pow2(uint64 v) { uint64 tmp = (uint64)1 << MDFN_log2(v); return tmp << (tmp < v); }
static INLINE uint64 round_up_pow2(int32 v) { return round_up_pow2((uint32)v); }
static INLINE uint64 round_up_pow2(int64 v) { return round_up_pow2((uint64)v); }
// Rounds to the nearest power of 2(treats input as unsigned to a degree, but be aware of integer promotion rules).
static INLINE uint64 round_nearest_pow2(uint32 v, bool round_half_up = true) { uint64 tmp = (uint64)1 << MDFN_log2(v); return tmp << (v && (((v - tmp) << 1) >= (tmp + !round_half_up))); }
static INLINE uint64 round_nearest_pow2(uint64 v, bool round_half_up = true) { uint64 tmp = (uint64)1 << MDFN_log2(v); return tmp << (v && (((v - tmp) << 1) >= (tmp + !round_half_up))); }
static INLINE uint64 round_nearest_pow2(int32 v, bool round_half_up = true) { return round_nearest_pow2((uint32)v, round_half_up); }
static INLINE uint64 round_nearest_pow2(int64 v, bool round_half_up = true) { return round_nearest_pow2((uint64)v, round_half_up); }
// Some compilers' optimizers and some platforms might fubar the generated code from these macros,
// so some tests are run in...tests.cpp
#define sign_8_to_s16(_value) ((int16)(int8)(_value))
#define sign_9_to_s16(_value) (((int16)((unsigned int)(_value) << 7)) >> 7)
#define sign_10_to_s16(_value) (((int16)((uint32)(_value) << 6)) >> 6)
#define sign_11_to_s16(_value) (((int16)((uint32)(_value) << 5)) >> 5)
#define sign_12_to_s16(_value) (((int16)((uint32)(_value) << 4)) >> 4)
#define sign_13_to_s16(_value) (((int16)((uint32)(_value) << 3)) >> 3)
#define sign_14_to_s16(_value) (((int16)((uint32)(_value) << 2)) >> 2)
#define sign_15_to_s16(_value) (((int16)((uint32)(_value) << 1)) >> 1)
// This obviously won't convert higher-than-32 bit numbers to signed 32-bit ;)
// Also, this shouldn't be used for 8-bit and 16-bit signed numbers, since you can
// convert those faster with typecasts...
#define sign_x_to_s32(_bits, _value) (((int32)((uint32)(_value) << (32 - _bits))) >> (32 - _bits))
static INLINE int32 clamp_to_u8(int32 i)
{
if(i & 0xFFFFFF00)
i = (((~i) >> 30) & 0xFF);
return(i);
}
static INLINE int32 clamp_to_u16(int32 i)
{
if(i & 0xFFFF0000)
i = (((~i) >> 31) & 0xFFFF);
return(i);
}
template<typename T, typename U, typename V> static INLINE void clamp(T *val, U minimum, V maximum)
{
if(*val < minimum)
{
//printf("Warning: clamping to minimum(%d)\n", (int)minimum);
*val = minimum;
}
if(*val > maximum)
{
//printf("Warning: clamping to maximum(%d)\n", (int)maximum);
*val = maximum;
}
}
#endif

View File

@ -1,328 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* mem-handler.inc:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
uint8 MDFN_FASTCALL mem_peekbyte(const v810_timestamp_t timestamp, const uint32 A)
{
if (A <= 0x001FFFFF)
return (RAM[A]);
else if (A <= 0x00FFFFFF)
return (0xFF);
else if (A >= 0xF0000000)
return (BIOSROM[A & 0xFFFFF]);
else if (FXSCSIROM && A >= 0x80780000 && A <= 0x807FFFFF)
{
return (FXSCSIROM[A & 0x7FFFF]);
}
return (0xFF);
}
uint16 MDFN_FASTCALL mem_peekhword(const v810_timestamp_t timestamp, const uint32 A) // TODO: Full memory map peeking.
{
if (A <= 0x001FFFFF)
return MDFN_de16lsb<true>(&RAM[A]);
else if (A <= 0x00FFFFFF)
return 0xFFFF;
else if (A >= 0xF0000000)
return MDFN_de16lsb<true>(&BIOSROM[A & 0xFFFFF]);
else if (FXSCSIROM && A >= 0x80780000 && A <= 0x807FFFFF)
return MDFN_de16lsb<true>(&FXSCSIROM[A & 0x7FFFF]);
return 0xFFFF;
}
static uint8 MDFN_FASTCALL mem_rbyte(v810_timestamp_t &timestamp, uint32 A)
{
if (A <= 0x001FFFFF)
{
RAMLPCHECK;
return (RAM[A]);
}
else if (A <= 0x00FFFFFF)
{
RAMLPCHECK;
return (0xFF);
}
else if (A >= 0xF0000000) // BIOS ROM mirrored throughout 0xF0000000-0xFFFFFFFF, the "official" location
// is at 0xFFF00000(what about on a PC-FXGA??)
{
timestamp += 2;
return (BIOSROM[A & 0xFFFFF]);
}
else if (A >= 0xE0000000 && A <= 0xE7FFFFFF && !(A & 1))
{
//printf("%d\n", (A - 0xE0000000) >> 1);
return (BackupRAM[(A & 0xFFFF) >> 1]);
}
else if (A >= 0xE8000000 && A <= 0xE9FFFFFF)
{
if (!(BackupControl & 0x2))
{
FXDBG("Read8 from external BRAM when not enabled.");
}
return (ExBackupRAM[(A & 0xFFFF) >> 1]);
}
else if (A >= 0x80000000 && A <= 0x807FFFFF)
{
//FXDBG("Mem->IO B Read Translation: %08x -> %08x", A, A & 0x7FFFFF);
return (port_rbyte(timestamp, A & 0x7FFFFF));
}
FXDBG("Unknown byte read: %08x", A);
return (0xFF);
}
static uint16 MDFN_FASTCALL mem_rhword(v810_timestamp_t &timestamp, uint32 A)
{
if (A <= 0x001FFFFF)
{
RAMLPCHECK;
return MDFN_de16lsb<true>(&RAM[A]);
}
else if (A <= 0x00FFFFFF)
{
RAMLPCHECK;
return (0xFFFF);
}
else if (A >= 0xF0000000) // BIOS ROM mirrored throughout 0xF0000000-0xFFFFFFFF, the "official" location
// is at 0xFFF00000
{
timestamp += 2;
return MDFN_de16lsb<true>(&BIOSROM[A & 0xFFFFF]);
}
else if (A >= 0xA0000000 && A <= 0xA3FFFFFF)
{
timestamp += 4;
return (FXVCE_Read16(0x4));
}
else if (A >= 0xA4000000 && A <= 0xA7FFFFFF)
{
timestamp += 4;
return (fx_vdc_chips[0]->Read16(1));
}
else if (A >= 0xA8000000 && A <= 0xABFFFFFF)
{
timestamp += 4;
return (fx_vdc_chips[1]->Read16(1));
}
else if (A >= 0xAC000000 && A <= 0xAFFFFFFF)
{
timestamp += 4;
return (KING_Read16(timestamp, 0x604));
}
else if (A >= 0xB0000000 && A <= 0xBFFFFFFF) // Write only
{
return (0);
}
else if (A >= 0xE0000000 && A <= 0xE7FFFFFF)
{
//printf("%d\n", (A - 0xE0000000) >> 1);
return (BackupRAM[(A & 0xFFFF) >> 1]);
}
else if (A >= 0xE8000000 && A <= 0xE9FFFFFF)
{
if (!(BackupControl & 0x2))
{
FXDBG("Read16 from external BRAM when not enabled.");
}
return (ExBackupRAM[(A & 0xFFFF) >> 1]);
}
else if (A >= 0xF8000000 && A <= 0xFFEFFFFF) // PIO
{
FXDBG("PIO H Read: %08x", A);
return (0x00);
}
else if (A >= 0x80000000 && A <= 0x807FFFFF)
{
//FXDBG("Mem->IO H Read Translation: %08x -> %08x", A, A & 0x7FFFFF);
return (port_rhword(timestamp, A & 0x7FFFFF));
}
FXDBG("Unknown hword read: %08x", A);
return (0xFFFF);
}
static uint32 MDFN_FASTCALL mem_rword(v810_timestamp_t &timestamp, uint32 A)
{
if (A <= 0x001FFFFF)
{
RAMLPCHECK;
return MDFN_de32lsb<true>(&RAM[A]);
}
else if (A <= 0x00FFFFFF)
{
RAMLPCHECK;
return (0xFFFFFFFF);
}
else if (A >= 0xB0000000 && A <= 0xBFFFFFFF) // Write only
{
return (0);
}
else
{
uint32 ret;
FXDBG("Warning: mem_rword() called for 16-bit bus access: %08x", A);
ret = mem_rhword(timestamp, A);
ret |= mem_rhword(timestamp, A | 2) << 16;
return (ret);
}
FXDBG("Unknown word read: %08x", A);
return (0xFFFFFFFF);
}
static void MDFN_FASTCALL mem_wbyte(v810_timestamp_t &timestamp, uint32 A, uint8 V)
{
if (A <= 0x001FFFFF)
{
RAMLPCHECK;
RAM[A] = V;
}
else if (A <= 0x00FFFFFF)
{
RAMLPCHECK;
}
else if (A >= 0xE0000000 && A <= 0xE7FFFFFF && !(A & 1))
{
if (BackupControl & 0x1)
{
//BackupSignalDirty |= (BackupRAM[(A & 0xFFFF) >> 1] != V);
BackupRAM[(A & 0xFFFF) >> 1] = V;
}
}
else if (A >= 0xE8000000 && A <= 0xE9FFFFFF)
{
//printf("ExWrite: %08x", A);
if (BackupControl & 0x2)
{
//BackupSignalDirty |= (ExBackupRAM[(A & 0xFFFF) >> 1] != V);
ExBackupRAM[(A & 0xFFFF) >> 1] = V;
}
}
else if (A >= 0xF8000000 && A <= 0xFFEFFFFF)
{
FXDBG("PIO B Write: %08x %02x", A, V);
// PIO?
}
else if (A >= 0x80000000 && A <= 0x807FFFFF)
{
//FXDBG("Mem->IO B Write Translation: %08x %02x -> %08x", A, V, A & 0x7FFFFF);
port_wbyte(timestamp, A & 0x7FFFFF, V);
}
}
static void MDFN_FASTCALL mem_whword(v810_timestamp_t &timestamp, uint32 A, uint16 V)
{
if (A <= 0x001FFFFF)
{
RAMLPCHECK;
MDFN_en16lsb<true>(&RAM[A], V);
}
else if (A <= 0x00FFFFFF)
{
RAMLPCHECK;
}
else if (A >= 0xE0000000 && A <= 0xE7FFFFFF)
{
if (BackupControl & 0x1)
{
//BackupSignalDirty |= (BackupRAM[(A & 0xFFFF) >> 1] != (uint8)V);
BackupRAM[(A & 0xFFFF) >> 1] = (uint8)V;
}
}
else if (A >= 0xE8000000 && A <= 0xE9FFFFFF)
{
//printf("ExWrite16: %08x", A);
if (BackupControl & 0x2)
{
//BackupSignalDirty |= (ExBackupRAM[(A & 0xFFFF) >> 1] != (uint8)V);
ExBackupRAM[(A & 0xFFFF) >> 1] = (uint8)V;
}
}
else if (A >= 0xF8000000 && A <= 0xFFEFFFFF)
{
FXDBG("PIO H Write: %08x %04x", A, V);
// PIO?
}
else if (A >= 0xA0000000 && A <= 0xAFFFFFFF) // Read only
{
}
else if (A >= 0xB0000000 && A <= 0xB3FFFFFF)
{
timestamp += 2;
FXVCE_Write16(0x4, V);
}
else if (A >= 0xB4000000 && A <= 0xB7FFFFFF)
{
timestamp += 2;
fx_vdc_chips[0]->Write16(1, V);
}
else if (A >= 0xB8000000 && A <= 0xBBFFFFFF)
{
timestamp += 2;
fx_vdc_chips[1]->Write16(1, V);
}
else if (A >= 0xBC000000 && A <= 0xBFFFFFFF)
{
timestamp += 2;
KING_Write16(timestamp, 0x604, V);
}
else if (A >= 0x80000000 && A <= 0x807FFFFF)
{
//FXDBG("Mem->IO H Write Translation: %08x %04x -> %08x", A, V, A & 0x7FFFFF);
port_whword(timestamp, A & 0x7FFFFF, V);
}
else
{
FXDBG("Unknown hword write: %08x %04x", A, V);
}
}
static void MDFN_FASTCALL mem_wword(v810_timestamp_t &timestamp, uint32 A, uint32 V)
{
if (A <= 0x001FFFFF)
{
RAMLPCHECK;
MDFN_en32lsb<true>(&RAM[A], V);
}
else if (A <= 0x00FFFFFF)
{
RAMLPCHECK;
}
else if (A >= 0xA0000000 && A <= 0xAFFFFFFF) // Read only
{
}
else
{
FXDBG("Warning: mem_wword() called for 16-bit bus access: %08x", A);
mem_whword(timestamp, A, V);
mem_whword(timestamp, A | 2, V >> 16);
}
}

View File

@ -1,140 +0,0 @@
-------------------------
Hardware scaling+rotation
-------------------------
All Japan Female Pro Wrestling
Crazy zoom effects in the intro.
Anime Freak FX Vol. 1
Staff List text special effects.
Anime Freak FX Vol. 2
Crazy zoom effects in the intro.
Anime Freak FX Vol. 3
Staff List text special effects.
Chip Chan Kick
Name entry screen.
Cutey Honey FX
Map zoomin/zoomout.
Der Langrisser FX
Progress/Map(?) when starting a new scenario.
First Kiss Monogatari
Billboard current-day transition screen.
Kishin Douji Zenki Vajura Fight FX
Screen blorping after defeating Marubasu. Outside level where you fight the
possessed frog for effects on one of the backgrounds. (Other places too???)
Kokuu Hyouryuu Nirgends
While flying.
Konpeki no Kantai
Overhead map screen.
Last Imperial Prince
Title screen is flipped into place.
Lunatic Dawn
Map screen.
Megami Paradise II
Area transitions.
Miraculum
Title screen, and in the air ship.
Return to Zork
Background scaling.
Super Power League FX
Baseball field.
Tonari no Princess Rolfee
Scene transitions(sometimes).
Tyoushin Heiki Zeroigar
Second stage boss.
------------------
256 color VDC mode
------------------
Angelique Tenkuu no Requim
Angelique Special 2
Chip Chan Kick
Cybertech Custom screen, cutscenes.
Ojousama Sousamou
Tokimeki Card Paradise
---------------
Back cellophane
---------------
Last Imperial Prince
Screen darkening during dialogue, and upper/lower screen greenish tint bug afterwards...uses a non-black CCR value!
Lunatic Dawn
Background fadeouts.
PCE Fan Special CDROM Vol 2
Fadeouts and fadeins.
Sotsuguyou 2
Fadeouts and fadeins.
Team Innocent
Background fadeins.
------------------------------------------------
Bitstring Hardware I/O Map Mirrors in Memory Map
------------------------------------------------
Boundary Gate
Super Power League FX
----------------------------------
KING BG mode/microprogram mismatch
----------------------------------
Megami Paradise II
Tonari no Princess Rolfee
------------------
KING BG0 Subscreen
------------------
Angelique Special
Overhead map(probably a coding error on the game developers' part, but it's still
used to the extent that if it's not emulated, the map won't show).
----------
BIOS Notes
----------
CD+G Playback
Pausing/unpausing playback when playing a CD+G disc will cause corruption of the CD+G graphics.
Using the scan forward/reverse when playing a CD+G disc will cause massive corruption of the CD+G graphics.

View File

@ -1,821 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* Original skeleton write handler and PSG structure definition:
* Copyright (C) 2001 Charles MacDonald
*
* 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 "../defs.h"
#include "pce_psg.h"
#include <math.h>
#include <string.h>
// Frequency cache cutoff optimization threshold (<= FREQC7M_COT)
#define FREQC7M_COT 0x7 //0xA
void PCE_PSG::SetVolume(double new_volume)
{
for(int vl = 0; vl < 32; vl++)
{
double flub = 1.0 * new_volume * 8 / 6;
if(vl)
flub /= pow(2, (double)1 / 4 * vl); // ~1.5dB reduction per increment of vl
if(vl == 0x1F)
flub = 0;
for(int samp = 0; samp < 32; samp++)
{
int eff_samp;
if(revision == REVISION_HUC6280)
eff_samp = samp * 2;
else
eff_samp = samp * 2 - 0x1F;
dbtable[vl][samp] = (int32)(flub * eff_samp * 128); // * 256);
dbtable_volonly[vl] = (int32)(flub * 65536);
// dbtable[vl][samp] = (int32)(flub * eff_samp * 128);
// dbtable_volonly[vl] = (int32)(flub * 65536);
}
}
}
// Note: Changing the 0x1F(not that there should be) would require changing the channel pseudo-off volume check logic later on.
static const int scale_tab[] =
{
0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F
};
#define CLOCK_LFSR(lfsr) { unsigned int newbit = ((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 11) ^ (lfsr >> 12) ^ (lfsr >> 17)) & 1; lfsr = (lfsr >> 1) | (newbit << 17); }
static const int16 Phase_Filter[2][7] =
{
/* 0 */ { 35, 250, 579, 641, 425, 112, 6 }, // 2048
/* 1 */ { 6, 112, 425, 641, 579, 250, 35 }, // 2048
};
INLINE void PCE_PSG::UpdateOutputSub(const int32 timestamp, psg_channel *ch, const int32 samp0, const int32 samp1)
{
int32 delta[2];
delta[0] = samp0 - ch->blip_prev_samp[0];
delta[1] = samp1 - ch->blip_prev_samp[1];
const int16* c = Phase_Filter[(timestamp >> 1) & 1];
const int32 l = (timestamp >> 2) & 0xFFFF;
HRBufs[0][l + 0] += delta[0] * c[0];
HRBufs[0][l + 1] += delta[0] * c[1];
HRBufs[0][l + 2] += delta[0] * c[2];
HRBufs[0][l + 3] += delta[0] * c[3];
HRBufs[0][l + 4] += delta[0] * c[4];
HRBufs[0][l + 5] += delta[0] * c[5];
HRBufs[0][l + 6] += delta[0] * c[6];
HRBufs[1][l + 0] += delta[1] * c[0];
HRBufs[1][l + 1] += delta[1] * c[1];
HRBufs[1][l + 2] += delta[1] * c[2];
HRBufs[1][l + 3] += delta[1] * c[3];
HRBufs[1][l + 4] += delta[1] * c[4];
HRBufs[1][l + 5] += delta[1] * c[5];
HRBufs[1][l + 6] += delta[1] * c[6];
ch->blip_prev_samp[0] = samp0;
ch->blip_prev_samp[1] = samp1;
}
void PCE_PSG::UpdateOutput_Norm(const int32 timestamp, psg_channel *ch)
{
int sv = ch->dda;
UpdateOutputSub(timestamp, ch, dbtable[ch->vl[0]][sv],
dbtable[ch->vl[1]][sv]);
}
void PCE_PSG::UpdateOutput_Noise(const int32 timestamp, psg_channel *ch)
{
int sv = ((ch->lfsr & 1) << 5) - (ch->lfsr & 1); //(ch->lfsr & 0x1) ? 0x1F : 0;
UpdateOutputSub(timestamp, ch, dbtable[ch->vl[0]][sv],
dbtable[ch->vl[1]][sv]);
}
void PCE_PSG::UpdateOutput_Off(const int32 timestamp, psg_channel *ch)
{
UpdateOutputSub(timestamp, ch, 0, 0);
}
void PCE_PSG::UpdateOutput_Accum_HuC6280A(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
// 31(5-bit max) * 32 samples = 992
// 992 / 2 = 496
//
// 8 + 5 = 13
// 13 - 12 = 1
samp[0] = ((int32)dbtable_volonly[ch->vl[0]] * ((int32)ch->samp_accum - 496)) >> (8 + 5);
samp[1] = ((int32)dbtable_volonly[ch->vl[1]] * ((int32)ch->samp_accum - 496)) >> (8 + 5);
UpdateOutputSub(timestamp, ch, samp[0], samp[1]);
}
void PCE_PSG::UpdateOutput_Accum_HuC6280(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
samp[0] = ((int32)dbtable_volonly[ch->vl[0]] * (int32)ch->samp_accum) >> (8 + 5);
samp[1] = ((int32)dbtable_volonly[ch->vl[1]] * (int32)ch->samp_accum) >> (8 + 5);
UpdateOutputSub(timestamp, ch, samp[0], samp[1]);
}
// This function should always be called after RecalcFreqCache() (it's not called from RecalcFreqCache to avoid redundant code)
void PCE_PSG::RecalcUOFunc(int chnum)
{
psg_channel *ch = &channel[chnum];
//printf("UO Update: %d, %02x\n", chnum, ch->control);
if((revision != REVISION_HUC6280 && !(ch->control & 0xC0)) || (revision == REVISION_HUC6280 && !(ch->control & 0x80)))
ch->UpdateOutput = &PCE_PSG::UpdateOutput_Off;
else if(ch->noisectrl & ch->control & 0x80)
ch->UpdateOutput = &PCE_PSG::UpdateOutput_Noise;
// If the control for the channel is in waveform play mode, and the (real) playback frequency is too high, and the channel is either not the LFO modulator channel or
// if the LFO trigger bit(which halts the LFO modulator channel's waveform incrementing when set) is clear
else if((ch->control & 0xC0) == 0x80 && ch->freq_cache <= FREQC7M_COT && (chnum != 1 || !(lfoctrl & 0x80)) )
ch->UpdateOutput = UpdateOutput_Accum;
else
ch->UpdateOutput = &PCE_PSG::UpdateOutput_Norm;
}
void PCE_PSG::RecalcFreqCache(int chnum)
{
psg_channel *ch = &channel[chnum];
if(chnum == 0 && (lfoctrl & 0x03))
{
const uint32 shift = (((lfoctrl & 0x3) - 1) << 1);
uint8 la = channel[1].dda;
uint32 tmp_freq = (ch->frequency + ((uint32)(la - 0x10) << shift)) & 0xFFF;
ch->freq_cache = (tmp_freq ? tmp_freq : 4096) << 1;
}
else
{
ch->freq_cache = (ch->frequency ? ch->frequency : 4096) << 1;
if(chnum == 1 && (lfoctrl & 0x03))
ch->freq_cache *= lfofreq ? lfofreq : 256;
}
}
void PCE_PSG::RecalcNoiseFreqCache(int chnum)
{
psg_channel *ch = &channel[chnum];
int32 freq = 0x1F - (ch->noisectrl & 0x1F);
if(!freq)
freq = 0x20;
else
freq <<= 6;
freq <<= 1;
ch->noise_freq_cache = freq;
}
void PCE_PSG::PeekWave(const unsigned int ch, uint32 Address, uint32 Length, uint8 *Buffer)
{
assert(ch <= 5);
while(Length--)
{
Address &= 0x1F;
*Buffer = channel[ch].waveform[Address];
Address++;
Buffer++;
}
}
void PCE_PSG::PokeWave(const unsigned int ch, uint32 Address, uint32 Length, const uint8 *Buffer)
{
assert(ch <= 5);
while(Length--)
{
Address &= 0x1F;
channel[ch].samp_accum -= channel[ch].waveform[Address];
channel[ch].waveform[Address] = *Buffer & 0x1F;
channel[ch].samp_accum += channel[ch].waveform[Address];
Address++;
Buffer++;
}
}
uint32 PCE_PSG::GetRegister(const unsigned int id, char *special, const uint32 special_len)
{
uint32 value = 0xDEADBEEF;
const int ch = (id >> 8) & 0xF;
switch(id & 0xF0FF)
{
default: break;
case PSG_GSREG_SELECT:
value = select;
break;
case PSG_GSREG_GBALANCE:
value = globalbalance;
break;
case PSG_GSREG_LFOFREQ:
value = lfofreq;
break;
case PSG_GSREG_LFOCTRL:
value = lfoctrl;
break;
case PSG_GSREG_CH0_FREQ:
value = channel[ch].frequency;
break;
case PSG_GSREG_CH0_CTRL:
value = channel[ch].control;
break;
case PSG_GSREG_CH0_BALANCE:
value = channel[ch].balance;
break;
case PSG_GSREG_CH0_WINDEX:
value = channel[ch].waveform_index;
break;
case PSG_GSREG_CH0_SCACHE:
value = channel[ch].dda;
break;
case PSG_GSREG_CH0_NCTRL:
value = channel[ch].noisectrl;
break;
case PSG_GSREG_CH0_LFSR:
value = channel[ch].lfsr & 0x3FFFF;
break;
}
return(value);
}
void PCE_PSG::SetRegister(const unsigned int id, const uint32 value)
{
const int ch = (id >> 8) & 0xF;
switch(id & 0xF0FF)
{
default: break;
case PSG_GSREG_SELECT:
select = value & 0x07;
break;
case PSG_GSREG_GBALANCE:
globalbalance = value & 0xFF;
break;
case PSG_GSREG_LFOFREQ:
lfofreq = value & 0xFF;
break;
case PSG_GSREG_LFOCTRL:
lfoctrl = value & 0x83;
RecalcFreqCache(0);
RecalcUOFunc(0);
RecalcFreqCache(1);
RecalcUOFunc(1);
break;
case PSG_GSREG_CH0_FREQ:
channel[ch].frequency = value & 0xFFF;
RecalcFreqCache(ch);
RecalcUOFunc(ch);
break;
case PSG_GSREG_CH0_CTRL:
channel[ch].control = value & 0xFF;
RecalcFreqCache(ch);
RecalcUOFunc(ch);
break;
case PSG_GSREG_CH0_BALANCE:
channel[ch].balance = value & 0xFF;
break;
case PSG_GSREG_CH0_WINDEX:
channel[ch].waveform_index = value & 0x1F;
break;
case PSG_GSREG_CH0_SCACHE:
channel[ch].dda = value & 0x1F;
break;
case PSG_GSREG_CH0_NCTRL:
channel[ch].noisectrl = value & 0xFF;
RecalcNoiseFreqCache(ch);
RecalcUOFunc(ch);
break;
case PSG_GSREG_CH0_LFSR:
channel[ch].lfsr = value & 0x3FFFF;
break;
}
}
#if 0
void PSG_SetRegister(const unsigned int id, const uint32 value)
{
if(name == "Select")
PSG_Write(0x00, V);
else if(name == "GBalance")
PSG_Write(0x01, V);
else if(name == "LFOFreq")
{
PSG_Write(0x08, V);
}
else if(name == "LFOCtrl")
PSG_Write(0x09, V);
else if(!strncmp(name.c_str(), "CH", 2))
{
unsigned int psg_sel_save = select;
int ch = name[2] - '0';
char moomoo[64];
strncpy(moomoo, name.c_str() + 3, 63);
PSG_Write(0x00, ch);
if(!strcmp(moomoo, "Freq"))
{
PSG_Write(0x02, V);
PSG_Write(0x03, V >> 8);
}
else if(!strcmp(moomoo, "Ctrl"))
PSG_Write(0x04, V);
else if(!strcmp(moomoo, "Balance"))
PSG_Write(0x05, V);
else if(!strcmp(moomoo, "WIndex"))
psg.channel[ch].waveform_index = V & 0x1F;
else if(!strcmp(moomoo, "SCache"))
psg.channel[ch].dda = V & 0x1F;
else if(!strcmp(moomoo, "NCtrl") && ch < 4)
psg.channel[ch].noisectrl = V;
else if(!strcmp(moomoo, "LFSR") && ch < 4)
psg.channel[ch].lfsr = V & 0x3FFFF;
PSG_Write(0x00, psg_sel_save);
}
}
#endif
PCE_PSG::PCE_PSG(int32* hr_l, int32* hr_r, int want_revision)
{
//printf("Test: %u, %u\n", sizeof(psg_channel), (uint8*)&channel[0].balance - (uint8*)&channel[0].waveform[0]);
revision = want_revision;
switch(revision)
{
default:
abort();
break;
case REVISION_HUC6280:
UpdateOutput_Accum = &PCE_PSG::UpdateOutput_Accum_HuC6280;
break;
case REVISION_HUC6280A:
UpdateOutput_Accum = &PCE_PSG::UpdateOutput_Accum_HuC6280A;
break;
}
HRBufs[0] = hr_l;
HRBufs[1] = hr_r;
lastts = 0;
for(int ch = 0; ch < 6; ch++)
{
channel[ch].blip_prev_samp[0] = 0;
channel[ch].blip_prev_samp[1] = 0;
channel[ch].lastts = 0;
}
SetVolume(1.0); // Will build dbtable in the process.
Power(0);
}
PCE_PSG::~PCE_PSG()
{
}
int32 PCE_PSG::GetVL(const int chnum, const int lr)
{
psg_channel *ch = &channel[chnum];
const int gbal = 0x1F - scale_tab[(globalbalance >> (lr ? 0 : 4)) & 0xF];
const int bal = 0x1F - scale_tab[(ch->balance >> (lr ? 0 : 4)) & 0xF];
const int al = 0x1F - (ch->control & 0x1F);
int vol_reduction;
vol_reduction = gbal + bal + al;
if(vol_reduction > 0x1F)
vol_reduction = 0x1F;
return(vol_reduction);
}
void PCE_PSG::Write(int32 timestamp, uint8 A, uint8 V)
{
A &= 0x0F;
if(A == 0x00)
{
select = (V & 0x07);
return;
}
Update(timestamp);
psg_channel *ch = &channel[select];
//if(A == 0x01 || select == 5)
// printf("Write Ch: %d %04x %02x, %d\n", select, A, V, timestamp);
switch(A)
{
default: break;
case 0x01: /* Global sound balance */
globalbalance = V;
vol_pending = true;
break;
case 0x02: /* Channel frequency (LSB) */
if(select > 5) return; // no more than 6 channels, silly game.
ch->frequency = (ch->frequency & 0x0F00) | V;
RecalcFreqCache(select);
RecalcUOFunc(select);
break;
case 0x03: /* Channel frequency (MSB) */
if(select > 5) return; // no more than 6 channels, silly game.
ch->frequency = (ch->frequency & 0x00FF) | ((V & 0x0F) << 8);
RecalcFreqCache(select);
RecalcUOFunc(select);
break;
case 0x04: /* Channel enable, DDA, volume */
if(select > 5) return; // no more than 6 channels, silly game.
if((ch->control & 0x40) && !(V & 0x40))
{
ch->waveform_index = 0;
ch->dda = ch->waveform[ch->waveform_index];
ch->counter = ch->freq_cache;
}
if(!(ch->control & 0x80) && (V & 0x80))
{
if(!(V & 0x40))
{
ch->waveform_index = (ch->waveform_index + 1) & 0x1F;
ch->dda = ch->waveform[ch->waveform_index];
}
}
ch->control = V;
RecalcFreqCache(select);
RecalcUOFunc(select);
vol_pending = true;
break;
case 0x05: /* Channel balance */
if(select > 5) return; // no more than 6 channels, silly game.
ch->balance = V;
vol_pending = true;
break;
case 0x06: /* Channel waveform data */
if(select > 5) return; // no more than 6 channels, silly game.
V &= 0x1F;
if(!(ch->control & 0x40))
{
ch->samp_accum -= ch->waveform[ch->waveform_index];
ch->waveform[ch->waveform_index] = V;
ch->samp_accum += ch->waveform[ch->waveform_index];
}
if((ch->control & 0xC0) == 0x00)
ch->waveform_index = ((ch->waveform_index + 1) & 0x1F);
if(ch->control & 0x80)
{
// According to my tests(on SuperGrafx), writing to this channel
// will update the waveform value cache/latch regardless of DDA mode being enabled.
ch->dda = V;
}
break;
case 0x07: /* Noise enable and frequency */
if(select > 5) return; // no more than 6 channels, silly game.
if(select >= 4)
{
ch->noisectrl = V;
RecalcNoiseFreqCache(select);
RecalcUOFunc(select);
}
break;
case 0x08: /* LFO frequency */
lfofreq = V & 0xFF;
//printf("LFO Freq: %02x\n", V);
break;
case 0x09: /* LFO trigger and control */
//printf("LFO Ctrl: %02x\n", V);
if(V & 0x80)
{
channel[1].waveform_index = 0;
channel[1].dda = channel[1].waveform[channel[1].waveform_index];
channel[1].counter = channel[1].freq_cache;
}
lfoctrl = V;
RecalcFreqCache(0);
RecalcUOFunc(0);
RecalcFreqCache(1);
RecalcUOFunc(1);
break;
}
}
// Don't use INLINE, which has always_inline in it, due to gcc's inability to cope with the type of recursion
// used in this function.
void PCE_PSG::RunChannel(int chc, int32 timestamp, const bool LFO_On)
{
psg_channel *ch = &channel[chc];
int32 running_timestamp = ch->lastts;
int32 run_time = timestamp - ch->lastts;
ch->lastts = timestamp;
if(!run_time)
return;
(this->*ch->UpdateOutput)(running_timestamp, ch);
if(chc >= 4)
{
int32 freq = ch->noise_freq_cache;
ch->noisecount -= run_time;
if(&PCE_PSG::UpdateOutput_Noise == ch->UpdateOutput)
while(ch->noisecount <= 0)
{
CLOCK_LFSR(ch->lfsr);
UpdateOutput_Noise(timestamp + ch->noisecount, ch);
ch->noisecount += freq;
}
else
while(ch->noisecount <= 0)
{
CLOCK_LFSR(ch->lfsr);
ch->noisecount += freq;
}
}
// D7 of control is 0, don't clock the counter at all.
// D7 of lfocontrol is 1(and chc == 1), don't clock the counter at all(not sure about this)
// In DDA mode, don't clock the counter.
// (Noise being enabled isn't handled here since AFAIK it doesn't disable clocking of the waveform portion, its sound just overrides the sound from
// the waveform portion when the noise enable bit is set, which is handled in our RecalcUOFunc).
if(!(ch->control & 0x80) || (chc == 1 && (lfoctrl & 0x80)) || (ch->control & 0x40))
return;
ch->counter -= run_time;
if(!LFO_On && ch->freq_cache <= FREQC7M_COT)
{
if(ch->counter <= 0)
{
const int32 inc_count = ((0 - ch->counter) / ch->freq_cache) + 1;
ch->counter += inc_count * ch->freq_cache;
ch->waveform_index = (ch->waveform_index + inc_count) & 0x1F;
ch->dda = ch->waveform[ch->waveform_index];
}
}
while(ch->counter <= 0)
{
ch->waveform_index = (ch->waveform_index + 1) & 0x1F;
ch->dda = ch->waveform[ch->waveform_index];
(this->*ch->UpdateOutput)(timestamp + ch->counter, ch);
if(LFO_On)
{
RunChannel(1, timestamp + ch->counter, false);
RecalcFreqCache(0);
RecalcUOFunc(0);
ch->counter += (ch->freq_cache <= FREQC7M_COT) ? FREQC7M_COT : ch->freq_cache; // Not particularly accurate, but faster.
}
else
ch->counter += ch->freq_cache;
}
}
void PCE_PSG::UpdateSubLFO(int32 timestamp)
{
for(int chc = 0; chc < 6; chc++)
RunChannel(chc, timestamp, chc == 0);
}
void PCE_PSG::UpdateSubNonLFO(int32 timestamp)
{
for(int chc = 0; chc < 6; chc++)
RunChannel(chc, timestamp, false);
}
void PCE_PSG::Update(int32 timestamp)
{
int32 run_time = timestamp - lastts;
if(vol_pending && !vol_update_counter && !vol_update_which)
{
vol_update_counter = 1;
vol_pending = false;
}
bool lfo_on = (bool)(lfoctrl & 0x03);
if(lfo_on)
{
if(!(channel[1].control & 0x80) || (lfoctrl & 0x80))
{
lfo_on = 0;
RecalcFreqCache(0);
RecalcUOFunc(0);
}
}
int32 clocks = run_time;
int32 running_timestamp = lastts;
while(clocks > 0)
{
int32 chunk_clocks = clocks;
if(vol_update_counter > 0 && chunk_clocks > vol_update_counter)
chunk_clocks = vol_update_counter;
running_timestamp += chunk_clocks;
clocks -= chunk_clocks;
if(lfo_on)
UpdateSubLFO(running_timestamp);
else
UpdateSubNonLFO(running_timestamp);
if(vol_update_counter > 0)
{
vol_update_counter -= chunk_clocks;
if(!vol_update_counter)
{
const int phase = vol_update_which & 1;
const int lr = ((vol_update_which >> 1) & 1) ^ 1;
const int chnum = vol_update_which >> 2;
if(!phase)
{
//printf("Volume update(Read, %d since last): ch=%d, lr=%d, ts=%d\n", running_timestamp - last_read, chnum, lr, running_timestamp);
if(chnum < 6)
{
vol_update_vllatch = GetVL(chnum, lr);
}
//last_read = running_timestamp;
}
else
{
// printf("Volume update(Apply): ch=%d, lr=%d, ts=%d\n", chnum, lr, running_timestamp);
if(chnum < 6)
{
channel[chnum].vl[lr] = vol_update_vllatch;
}
//last_apply = running_timestamp;
}
vol_update_which = (vol_update_which + 1) & 0x1F;
if(vol_update_which)
vol_update_counter = phase ? 1 : 255;
else if(vol_pending)
{
vol_update_counter = phase ? 1 : 255;
vol_pending = false;
}
}
}
lastts = running_timestamp;
}
}
void PCE_PSG::ResetTS(int32 ts_base)
{
lastts = ts_base;
for(int chc = 0; chc < 6; chc++)
channel[chc].lastts = ts_base;
}
void PCE_PSG::Power(const int32 timestamp)
{
// Not sure about power-on values, these are mostly just intuitive guesses(with some laziness thrown in).
if(timestamp != lastts)
Update(timestamp);
// Don't memset channel to 0, there's stuff like lastts and blip_prev_samp that shouldn't be altered on Power().
select = 0;
globalbalance = 0;
lfofreq = 0;
lfoctrl = 0;
for(int ch = 0; ch < 6; ch++)
{
channel[ch].frequency = 0;
channel[ch].control = 0x00;
channel[ch].balance = 0;
memset(channel[ch].waveform, 0, 32);
channel[ch].samp_accum = 0;
channel[ch].waveform_index = 0;
channel[ch].dda = 0x00;
channel[ch].noisectrl = 0x00;
channel[ch].vl[0] = 0x1F;
channel[ch].vl[1] = 0x1F;
channel[ch].samp_accum = 0;
RecalcFreqCache(ch);
RecalcUOFunc(ch);
channel[ch].counter = channel[ch].freq_cache;
if(ch >= 4)
{
RecalcNoiseFreqCache(ch);
}
channel[ch].noisecount = 1;
channel[ch].lfsr = 1;
}
vol_pending = false;
vol_update_counter = 0;
vol_update_which = 0;
}

View File

@ -1,187 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* Original skeleton write handler and PSG structure definition:
* Copyright (C) 2001 Charles MacDonald
*
* 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
*/
#ifndef _PCE_PSG_H
#define _PCE_PSG_H
class PCE_PSG;
struct psg_channel
{
uint8 waveform[32]; /* Waveform data */
uint8 waveform_index; /* Waveform data index */
uint8 dda;
uint8 control; /* Channel enable, DDA, volume */
uint8 noisectrl; /* Noise enable/ctrl (channels 4,5 only) */
int32 vl[2]; //vll, vlr;
int32 counter;
void (PCE_PSG::*UpdateOutput)(const int32 timestamp, psg_channel *ch);
uint32 freq_cache;
uint32 noise_freq_cache; // Channel 4,5 only
int32 noisecount;
uint32 lfsr;
int32 samp_accum; // The result of adding up all the samples in the waveform buffer(part of an optimization for high-frequency playback).
int32 blip_prev_samp[2];
int32 lastts;
uint16 frequency; /* Channel frequency */
uint8 balance; /* Channel balance */
};
// Only CH4 and CH5 have NCTRL and LFSR, but it's here for the other channels for "consistency".
enum
{
PSG_GSREG_CH0_FREQ = 0x000,
// PSG_GSREG_CH0_COUNTER,
PSG_GSREG_CH0_CTRL,
PSG_GSREG_CH0_BALANCE,
PSG_GSREG_CH0_WINDEX,
PSG_GSREG_CH0_SCACHE,
PSG_GSREG_CH0_NCTRL,
PSG_GSREG_CH0_LFSR,
PSG_GSREG_CH1_FREQ = 0x100,
// PSG_GSREG_CH1_COUNTER,
PSG_GSREG_CH1_CTRL,
PSG_GSREG_CH1_BALANCE,
PSG_GSREG_CH1_WINDEX,
PSG_GSREG_CH1_SCACHE,
PSG_GSREG_CH1_NCTRL,
PSG_GSREG_CH1_LFSR,
PSG_GSREG_CH2_FREQ = 0x200,
// PSG_GSREG_CH2_COUNTER,
PSG_GSREG_CH2_CTRL,
PSG_GSREG_CH2_BALANCE,
PSG_GSREG_CH2_WINDEX,
PSG_GSREG_CH2_SCACHE,
PSG_GSREG_CH2_NCTRL,
PSG_GSREG_CH2_LFSR,
PSG_GSREG_CH3_FREQ = 0x300,
// PSG_GSREG_CH3_COUNTER,
PSG_GSREG_CH3_CTRL,
PSG_GSREG_CH3_BALANCE,
PSG_GSREG_CH3_WINDEX,
PSG_GSREG_CH3_SCACHE,
PSG_GSREG_CH3_NCTRL,
PSG_GSREG_CH3_LFSR,
PSG_GSREG_CH4_FREQ = 0x400,
// PSG_GSREG_CH4_COUNTER,
PSG_GSREG_CH4_CTRL,
PSG_GSREG_CH4_BALANCE,
PSG_GSREG_CH4_WINDEX,
PSG_GSREG_CH4_SCACHE,
PSG_GSREG_CH4_NCTRL,
PSG_GSREG_CH4_LFSR,
PSG_GSREG_CH5_FREQ = 0x500,
// PSG_GSREG_CH5_COUNTER,
PSG_GSREG_CH5_CTRL,
PSG_GSREG_CH5_BALANCE,
PSG_GSREG_CH5_WINDEX,
PSG_GSREG_CH5_SCACHE,
PSG_GSREG_CH5_NCTRL,
PSG_GSREG_CH5_LFSR,
PSG_GSREG_SELECT = 0x1000,
PSG_GSREG_GBALANCE,
PSG_GSREG_LFOFREQ,
PSG_GSREG_LFOCTRL,
_PSG_GSREG_COUNT
};
class PCE_PSG
{
public:
enum
{
REVISION_HUC6280 = 0,
REVISION_HUC6280A,
_REVISION_COUNT
};
PCE_PSG(int32 *hr_l, int32 *hr_r, int want_revision)
MDFN_COLD;
~PCE_PSG() MDFN_COLD;
void Power(const int32 timestamp) MDFN_COLD;
void Write(int32 timestamp, uint8 A, uint8 V);
void SetVolume(double new_volume);
void Update(int32 timestamp);
void ResetTS(int32 ts_base = 0);
// TODO: timestamp
uint32 GetRegister(const unsigned int id, char *special, const uint32 special_len);
void SetRegister(const unsigned int id, const uint32 value);
void PeekWave(const unsigned int ch, uint32 Address, uint32 Length, uint8 *Buffer);
void PokeWave(const unsigned int ch, uint32 Address, uint32 Length, const uint8 *Buffer);
private:
void UpdateSubLFO(int32 timestamp);
void UpdateSubNonLFO(int32 timestamp);
void RecalcUOFunc(int chnum);
void UpdateOutputSub(const int32 timestamp, psg_channel *ch, const int32 samp0, const int32 samp1);
void UpdateOutput_Off(const int32 timestamp, psg_channel *ch);
void UpdateOutput_Accum_HuC6280(const int32 timestamp, psg_channel *ch);
void UpdateOutput_Accum_HuC6280A(const int32 timestamp, psg_channel *ch);
void UpdateOutput_Norm(const int32 timestamp, psg_channel *ch);
void UpdateOutput_Noise(const int32 timestamp, psg_channel *ch);
void (PCE_PSG::*UpdateOutput_Accum)(const int32 timestamp, psg_channel *ch);
int32 GetVL(const int chnum, const int lr);
void RecalcFreqCache(int chnum);
void RecalcNoiseFreqCache(int chnum);
void RunChannel(int chc, int32 timestamp, bool LFO_On);
uint8 select; /* Selected channel (0-5) */
uint8 globalbalance; /* Global sound balance */
uint8 lfofreq; /* LFO frequency */
uint8 lfoctrl; /* LFO control */
int32 vol_update_counter;
int32 vol_update_which;
int32 vol_update_vllatch;
bool vol_pending;
psg_channel channel[6];
int32 lastts;
int revision;
int32 *HRBufs[2];
int32 dbtable_volonly[32];
int32 dbtable[32][32];
};
#endif

View File

@ -1,954 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* pcfx.cpp:
** Copyright (C) 2006-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "pcfx.h"
#include "soundbox.h"
#include "input.h"
#include "king.h"
#include "timer.h"
#include "interrupt.h"
#include "rainbow.h"
#include "huc6273.h"
#include "fxscsi.h"
#include "cdrom/cdromif.h"
#include "cdrom/scsicd.h"
//#include <mednafen/mempatcher.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include "../emulibc/emulibc.h"
#include "../emulibc/waterboxcore.h"
namespace MDFN_IEN_PCFX
{
/* FIXME: soundbox, vce, vdc, rainbow, and king store wait states should be 4, not 2, but V810 has write buffers which can mask wait state penalties.
This is a hack to somewhat address the issue, but to really fix it, we need to handle write buffer emulation in the V810 emulation core itself.
*/
static std::vector<CDIF *> *cdifs = NULL;
V810 PCFX_V810;
static uint8 *BIOSROM = NULL; // 1MB
static uint8 *RAM = NULL; // 2MB
static uint8 *FXSCSIROM = NULL; // 512KiB
static uint32 RAM_LPA; // Last page access
static const int RAM_PageSize = 2048;
static const int RAM_PageNOTMask = ~(RAM_PageSize - 1);
static uint16 Last_VDC_AR[2];
static bool WantHuC6273 = FALSE;
//static
VDC *fx_vdc_chips[2];
static uint16 BackupControl;
static uint8 BackupRAM[0x8000], ExBackupRAM[0x8000];
static uint8 ExBusReset; // I/O Register at 0x0700
static bool Lagged;
static void (*InputCallback)();
// Checks to see if this main-RAM-area access
// is in the same DRAM page as the last access.
#define RAMLPCHECK \
{ \
if ((A & RAM_PageNOTMask) != RAM_LPA) \
{ \
timestamp += 3; \
RAM_LPA = A & RAM_PageNOTMask; \
} \
}
static v810_timestamp_t next_pad_ts, next_timer_ts, next_adpcm_ts, next_king_ts;
void PCFX_FixNonEvents(void)
{
if (next_pad_ts & 0x40000000)
next_pad_ts = PCFX_EVENT_NONONO;
if (next_timer_ts & 0x40000000)
next_timer_ts = PCFX_EVENT_NONONO;
if (next_adpcm_ts & 0x40000000)
next_adpcm_ts = PCFX_EVENT_NONONO;
if (next_king_ts & 0x40000000)
next_king_ts = PCFX_EVENT_NONONO;
}
void PCFX_Event_Reset(void)
{
next_pad_ts = PCFX_EVENT_NONONO;
next_timer_ts = PCFX_EVENT_NONONO;
next_adpcm_ts = PCFX_EVENT_NONONO;
next_king_ts = PCFX_EVENT_NONONO;
}
static INLINE uint32 CalcNextTS(void)
{
v810_timestamp_t next_timestamp = next_king_ts;
if (next_timestamp > next_pad_ts)
next_timestamp = next_pad_ts;
if (next_timestamp > next_timer_ts)
next_timestamp = next_timer_ts;
if (next_timestamp > next_adpcm_ts)
next_timestamp = next_adpcm_ts;
return (next_timestamp);
}
static void RebaseTS(const v810_timestamp_t timestamp, const v810_timestamp_t new_base_timestamp)
{
assert(next_pad_ts > timestamp);
assert(next_timer_ts > timestamp);
assert(next_adpcm_ts > timestamp);
assert(next_king_ts > timestamp);
next_pad_ts -= (timestamp - new_base_timestamp);
next_timer_ts -= (timestamp - new_base_timestamp);
next_adpcm_ts -= (timestamp - new_base_timestamp);
next_king_ts -= (timestamp - new_base_timestamp);
//printf("RTS: %d %d %d %d\n", next_pad_ts, next_timer_ts, next_adpcm_ts, next_king_ts);
}
void PCFX_SetEvent(const int type, const v810_timestamp_t next_timestamp)
{
//assert(next_timestamp > PCFX_V810.v810_timestamp);
if (type == PCFX_EVENT_PAD)
next_pad_ts = next_timestamp;
else if (type == PCFX_EVENT_TIMER)
next_timer_ts = next_timestamp;
else if (type == PCFX_EVENT_ADPCM)
next_adpcm_ts = next_timestamp;
else if (type == PCFX_EVENT_KING)
next_king_ts = next_timestamp;
if (next_timestamp < PCFX_V810.GetEventNT())
PCFX_V810.SetEventNT(next_timestamp);
}
int32 MDFN_FASTCALL pcfx_event_handler(const v810_timestamp_t timestamp)
{
if (timestamp >= next_king_ts)
next_king_ts = KING_Update(timestamp);
if (timestamp >= next_pad_ts)
next_pad_ts = FXINPUT_Update(timestamp);
if (timestamp >= next_timer_ts)
next_timer_ts = FXTIMER_Update(timestamp);
if (timestamp >= next_adpcm_ts)
next_adpcm_ts = SoundBox_ADPCMUpdate(timestamp);
#if 1
assert(next_king_ts > timestamp);
assert(next_pad_ts > timestamp);
assert(next_timer_ts > timestamp);
assert(next_adpcm_ts > timestamp);
#endif
return (CalcNextTS());
}
static void ForceEventUpdates(const uint32 timestamp)
{
next_king_ts = KING_Update(timestamp);
next_pad_ts = FXINPUT_Update(timestamp);
next_timer_ts = FXTIMER_Update(timestamp);
next_adpcm_ts = SoundBox_ADPCMUpdate(timestamp);
//printf("Meow: %d\n", CalcNextTS());
PCFX_V810.SetEventNT(CalcNextTS());
//printf("FEU: %d %d %d %d\n", next_pad_ts, next_timer_ts, next_adpcm_ts, next_king_ts);
}
#include "io-handler.inc"
#include "mem-handler.inc"
typedef struct
{
int8 tracknum;
int8 format;
uint32 lba;
} CDGameEntryTrack;
typedef struct
{
const char *name;
const char *name_original; // Original non-Romanized text.
const uint32 flags; // Emulation flags.
const unsigned int discs; // Number of discs for this game.
CDGameEntryTrack tracks[2][100]; // 99 tracks and 1 leadout track
} CDGameEntry;
#define CDGE_FORMAT_AUDIO 0
#define CDGE_FORMAT_DATA 1
#define CDGE_FLAG_ACCURATE_V810 0x01
#define CDGE_FLAG_FXGA 0x02
static uint32 EmuFlags;
static const CDGameEntry GameList[] =
{
#include "gamedb.inc"
};
static void Emulate(EmulateSpecStruct *espec)
{
FXINPUT_Frame();
KING_StartFrame(fx_vdc_chips, espec); //espec->surface, &espec->DisplayRect, espec->LineWidths, espec->skip);
v810_timestamp_t v810_timestamp;
v810_timestamp = PCFX_V810.Run(pcfx_event_handler);
PCFX_FixNonEvents();
// Call before resetting v810_timestamp
ForceEventUpdates(v810_timestamp);
//
// Call KING_EndFrame() before SoundBox_Flush(), otherwise CD-DA audio distortion will occur due to sound data being updated
// after it was needed instead of before.
//
KING_EndFrame(v810_timestamp);
//
// new_base_ts is guaranteed to be <= v810_timestamp
//
v810_timestamp_t new_base_ts;
espec->SoundBufSize = SoundBox_Flush(v810_timestamp, &new_base_ts, espec->SoundBuf, espec->SoundBufMaxSize, false);
KING_ResetTS(new_base_ts);
FXTIMER_ResetTS(new_base_ts);
FXINPUT_ResetTS(new_base_ts);
SoundBox_ResetTS(new_base_ts);
// Call this AFTER all the EndFrame/Flush/ResetTS stuff
RebaseTS(v810_timestamp, new_base_ts);
espec->MasterCycles = v810_timestamp - new_base_ts;
PCFX_V810.ResetTS(new_base_ts);
}
static void PCFX_Reset(void)
{
const uint32 timestamp = PCFX_V810.v810_timestamp;
//printf("Reset: %d\n", timestamp);
// Make sure all devices are synched to current timestamp before calling their Reset()/Power()(though devices should already do this sort of thing on their
// own, but it's not implemented for all of them yet, and even if it was all implemented this is also INSURANCE).
ForceEventUpdates(timestamp);
PCFX_Event_Reset();
RAM_LPA = 0;
ExBusReset = 0;
BackupControl = 0;
Last_VDC_AR[0] = 0;
Last_VDC_AR[1] = 0;
memset(RAM, 0x00, 2048 * 1024);
for (int i = 0; i < 2; i++)
{
int32 dummy_ne MDFN_NOWARN_UNUSED;
dummy_ne = fx_vdc_chips[i]->Reset();
}
KING_Reset(timestamp); // SCSICD_Power() is called from KING_Reset()
SoundBox_Reset(timestamp);
RAINBOW_Reset();
if (WantHuC6273)
HuC6273_Reset();
PCFXIRQ_Reset();
FXTIMER_Reset();
PCFX_V810.Reset();
// Force device updates so we can get new next event timestamp values.
ForceEventUpdates(timestamp);
}
static void PCFX_Power(void)
{
PCFX_Reset();
}
static void VDCA_IRQHook(bool asserted)
{
PCFXIRQ_Assert(PCFXIRQ_SOURCE_VDCA, asserted);
}
static void VDCB_IRQHook(bool asserted)
{
PCFXIRQ_Assert(PCFXIRQ_SOURCE_VDCB, asserted);
}
static MDFN_COLD void LoadCommon(std::vector<CDIF *> *CDInterfaces, const uint8_t *bios)
{
V810_Emu_Mode cpu_mode;
cpu_mode = (V810_Emu_Mode)Setting_CpuEmulation;
if (cpu_mode == _V810_EMU_MODE_COUNT)
{
cpu_mode = (EmuFlags & CDGE_FLAG_ACCURATE_V810) ? V810_EMU_MODE_ACCURATE : V810_EMU_MODE_FAST;
}
if (EmuFlags & CDGE_FLAG_FXGA)
{
//WantHuC6273 = TRUE;
}
MDFN_printf(_("V810 Emulation Mode: %s\n"), (cpu_mode == V810_EMU_MODE_ACCURATE) ? _("Accurate") : _("Fast"));
PCFX_V810.Init(cpu_mode, false);
uint32 RAM_Map_Addresses[1] = {0x00000000};
uint32 BIOSROM_Map_Addresses[1] = {0xFFF00000};
RAM = PCFX_V810.SetFastMap(RAM_Map_Addresses, 0x00200000, 1, _("RAM"), true);
BIOSROM = PCFX_V810.SetFastMap(BIOSROM_Map_Addresses, 0x00100000, 1, _("BIOS ROM"), false);
memcpy(BIOSROM, bios, 1024 * 1024);
/*{
std::string fxscsi_path = MDFN_GetSettingS("pcfx.fxscsi"); // For developers only, so don't make it convenient.
if (fxscsi_path != "0" && fxscsi_path != "" && fxscsi_path != "none")
{
FileStream FXSCSIFile(fxscsi_path, FileStream::MODE_READ);
uint32 FXSCSI_Map_Addresses[1] = {0x80780000};
FXSCSIROM = PCFX_V810.SetFastMap(FXSCSI_Map_Addresses, 0x0080000, 1, _("FX-SCSI ROM"), false);
FXSCSIFile.read(FXSCSIROM, 1024 * 512);
}
}*/
for (int i = 0; i < 2; i++)
{
fx_vdc_chips[i] = new VDC();
fx_vdc_chips[i]->SetUnlimitedSprites(Setting_NoSpriteLimit);
fx_vdc_chips[i]->SetVRAMSize(65536);
fx_vdc_chips[i]->SetWSHook(NULL);
fx_vdc_chips[i]->SetIRQHook(i ? VDCB_IRQHook : VDCA_IRQHook);
//fx_vdc_chips[0] = FXVDC_Init(PCFXIRQ_SOURCE_VDCA, Setting_NoSpriteLimit);
//fx_vdc_chips[1] = FXVDC_Init(PCFXIRQ_SOURCE_VDCB, Setting_NoSpriteLimit);
}
SoundBox_Init(Setting_AdpcmBuggy, Setting_AdpcmNoClicks);
RAINBOW_Init(Setting_ChromaInterpolate);
FXINPUT_Init();
FXTIMER_Init();
if (WantHuC6273)
HuC6273_Init();
KING_Init();
SCSICD_SetDisc(true, NULL, true);
#ifdef WANT_DEBUGGER
for (unsigned disc = 0; disc < CDInterfaces->size(); disc++)
{
CDUtility::TOC toc;
(*CDInterfaces)[disc]->ReadTOC(&toc);
for (int32 track = toc.first_track; track <= toc.last_track; track++)
{
if (toc.tracks[track].control & 0x4)
{
char tmpn[256], tmpln[256];
uint32 sectors;
trio_snprintf(tmpn, 256, "track%d-%d-%d", disc, track, toc.tracks[track].lba);
trio_snprintf(tmpln, 256, "CD - Disc %d/%d - Track %d/%d", disc + 1, (int)CDInterfaces->size(), track, toc.last_track - toc.first_track + 1);
sectors = toc.tracks[(track == toc.last_track) ? 100 : track + 1].lba - toc.tracks[track].lba;
ASpace_Add(PCFXDBG_GetAddressSpaceBytes, PCFXDBG_PutAddressSpaceBytes, tmpn, tmpln, 0, sectors * 2048);
}
}
}
#endif
// MDFNGameInfo->fps = (uint32)((double)7159090.90909090 / 455 / 263 * 65536 * 256);
//BackupSignalDirty = false;
//BackupSaveDelay = 0;
// Initialize backup RAM
memset(BackupRAM, 0, sizeof(BackupRAM));
memset(ExBackupRAM, 0, sizeof(ExBackupRAM));
static const uint8 BRInit00[] = {0x24, 0x8A, 0xDF, 0x50, 0x43, 0x46, 0x58, 0x53, 0x72, 0x61, 0x6D, 0x80,
0x00, 0x01, 0x01, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0xF9, 0x03, 0x00,
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
static const uint8 BRInit80[] = {0xF9, 0xFF, 0xFF};
memcpy(BackupRAM + 0x00, BRInit00, sizeof(BRInit00));
memcpy(BackupRAM + 0x80, BRInit80, sizeof(BRInit80));
static const uint8 ExBRInit00[] = {0x24, 0x8A, 0xDF, 0x50, 0x43, 0x46, 0x58, 0x43, 0x61, 0x72, 0x64, 0x80,
0x00, 0x01, 0x01, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0xF9, 0x03, 0x00,
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
static const uint8 ExBRInit80[] = {0xF9, 0xFF, 0xFF};
memcpy(ExBackupRAM + 0x00, ExBRInit00, sizeof(ExBRInit00));
memcpy(ExBackupRAM + 0x80, ExBRInit80, sizeof(ExBRInit80));
// Default to 16-bit bus.
for (int i = 0; i < 256; i++)
{
PCFX_V810.SetMemReadBus32(i, FALSE);
PCFX_V810.SetMemWriteBus32(i, FALSE);
}
// 16MiB RAM area.
PCFX_V810.SetMemReadBus32(0, TRUE);
PCFX_V810.SetMemWriteBus32(0, TRUE);
// Bitstring read range
for (int i = 0xA0; i <= 0xAF; i++)
{
PCFX_V810.SetMemReadBus32(i, FALSE); // Reads to the read range are 16-bit, and
PCFX_V810.SetMemWriteBus32(i, TRUE); // writes are 32-bit.
}
// Bitstring write range
for (int i = 0xB0; i <= 0xBF; i++)
{
PCFX_V810.SetMemReadBus32(i, TRUE); // Reads to the write range are 32-bit,
PCFX_V810.SetMemWriteBus32(i, FALSE); // but writes are 16-bit!
}
// BIOS area
for (int i = 0xF0; i <= 0xFF; i++)
{
PCFX_V810.SetMemReadBus32(i, FALSE);
PCFX_V810.SetMemWriteBus32(i, FALSE);
}
PCFX_V810.SetMemReadHandlers(mem_rbyte, mem_rhword, mem_rword);
PCFX_V810.SetMemWriteHandlers(mem_wbyte, mem_whword, mem_wword);
PCFX_V810.SetIOReadHandlers(port_rbyte, port_rhword, NULL);
PCFX_V810.SetIOWriteHandlers(port_wbyte, port_whword, NULL);
}
static void DoMD5CDVoodoo(std::vector<CDIF *> *CDInterfaces)
{
const CDGameEntry *found_entry = NULL;
CDUtility::TOC toc;
#if 0
puts("{");
puts(" ,");
puts(" ,");
puts(" 0,");
puts(" 1,");
puts(" {");
puts(" {");
for(int i = CDIF_GetFirstTrack(); i <= CDIF_GetLastTrack(); i++)
{
CDIF_Track_Format tf;
CDIF_GetTrackFormat(i, tf);
printf(" { %d, %s, %d },\n", i, (tf == CDIF_FORMAT_AUDIO) ? "CDIF_FORMAT_AUDIO" : "CDIF_FORMAT_MODE1", CDIF_GetTrackStartPositionLBA(i));
}
printf(" { -1, (CDIF_Track_Format)-1, %d },\n", CDIF_GetSectorCountLBA());
puts(" }");
puts(" }");
puts("},");
//exit(1);
#endif
for (unsigned if_disc = 0; if_disc < CDInterfaces->size(); if_disc++)
{
(*CDInterfaces)[if_disc]->ReadTOC(&toc);
if (toc.first_track == 1)
{
for (unsigned int g = 0; g < sizeof(GameList) / sizeof(CDGameEntry); g++)
{
const CDGameEntry *entry = &GameList[g];
assert(entry->discs == 1 || entry->discs == 2);
for (unsigned int disc = 0; disc < entry->discs; disc++)
{
const CDGameEntryTrack *et = entry->tracks[disc];
bool GameFound = TRUE;
while (et->tracknum != -1 && GameFound)
{
assert(et->tracknum > 0 && et->tracknum < 100);
if (toc.tracks[et->tracknum].lba != et->lba)
GameFound = FALSE;
if (((et->format == CDGE_FORMAT_DATA) ? 0x4 : 0x0) != (toc.tracks[et->tracknum].control & 0x4))
GameFound = FALSE;
et++;
}
if (et->tracknum == -1)
{
if ((et - 1)->tracknum != toc.last_track)
GameFound = FALSE;
if (et->lba != toc.tracks[100].lba)
GameFound = FALSE;
}
if (GameFound)
{
found_entry = entry;
goto FoundIt;
}
} // End disc count loop
}
}
FoundIt:;
if (found_entry)
{
EmuFlags = found_entry->flags;
printf("%s\n", found_entry->name);
printf("%s\n", found_entry->name_original);
break;
}
} // end: for(unsigned if_disc = 0; if_disc < CDInterfaces->size(); if_disc++)
}
// PC-FX BIOS will look at all data tracks(not just the first one), in contrast to the PCE CD BIOS, which only looks
// at the first data track.
static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
{
CDIF *cdiface = (*CDInterfaces)[0];
CDUtility::TOC toc;
uint8 sector_buffer[2048];
memset(sector_buffer, 0, sizeof(sector_buffer));
cdiface->ReadTOC(&toc);
for (int32 track = toc.first_track; track <= toc.last_track; track++)
{
if (toc.tracks[track].control & 0x4)
{
cdiface->ReadSector(sector_buffer, toc.tracks[track].lba, 1);
if (!strncmp("PC-FX:Hu_CD-ROM", (char *)sector_buffer, strlen("PC-FX:Hu_CD-ROM")))
{
return (TRUE);
}
if (!strncmp((char *)sector_buffer + 64, "PPPPHHHHOOOOTTTTOOOO____CCCCDDDD", 32))
return (true);
}
}
return (FALSE);
}
static MDFN_COLD void LoadCD(std::vector<CDIF *> *CDInterfaces, const uint8_t *bios)
{
EmuFlags = 0;
cdifs = CDInterfaces;
DoMD5CDVoodoo(CDInterfaces);
LoadCommon(CDInterfaces, bios);
MDFN_printf(_("Emulated CD-ROM drive speed: %ux\n"), (unsigned int)Setting_CdSpeed);
PCFX_Power();
}
}
using namespace MDFN_IEN_PCFX;
#define EXPORT extern "C" ECL_EXPORT
struct FrontendTOC
{
int32 FirstTrack;
int32 LastTrack;
int32 DiskType;
struct
{
int32 Adr;
int32 Control;
int32 Lba;
int32 Valid;
} Tracks[101];
};
static void (*ReadTOCCallback)(int disk, FrontendTOC *dest);
static void (*ReadSector2448Callback)(int disk, int lba, uint8 *dest);
EXPORT void SetCDCallbacks(void (*toccallback)(int disk, FrontendTOC *dest), void (*sectorcallback)(int disk, int lba, uint8 *dest))
{
ReadTOCCallback = toccallback;
ReadSector2448Callback = sectorcallback;
}
class MyCDIF : public CDIF
{
private:
int disk;
public:
MyCDIF(int disk) : disk(disk)
{
FrontendTOC t;
ReadTOCCallback(disk, &t);
disc_toc.first_track = t.FirstTrack;
disc_toc.last_track = t.LastTrack;
disc_toc.disc_type = t.DiskType;
for (int i = 0; i < 101; i++)
{
disc_toc.tracks[i].adr = t.Tracks[i].Adr;
disc_toc.tracks[i].control = t.Tracks[i].Control;
disc_toc.tracks[i].lba = t.Tracks[i].Lba;
disc_toc.tracks[i].valid = t.Tracks[i].Valid;
}
}
virtual void HintReadSector(int32 lba) {}
virtual bool ReadRawSector(uint8 *buf, int32 lba)
{
ReadSector2448Callback(disk, lba, buf);
return true;
}
};
static std::vector<CDIF *> CDInterfaces;
static uint32_t InputData[8];
struct MyFrameInfo : public FrameInfo
{
uint32_t Buttons[3]; // port 1, port 2, console
};
static EmulateSpecStruct Ess;
static int32_t LineWidths[480];
ECL_INVISIBLE static uint32_t FrameBuffer[1024 * 480];
EXPORT bool Init(int numDisks, const uint8_t *bios)
{
for (int i = 0; i < numDisks; i++)
CDInterfaces.push_back(new MyCDIF(i));
if (!TestMagicCD(&CDInterfaces))
return false;
LoadCD(&CDInterfaces, bios);
KING_SetPixelFormat();
SoundBox_SetSoundRate(44100);
SCSICD_SetDisc(false, CDInterfaces[0]);
// multitap is experimental emulation for a never release peripheral, so let's ignore it for now
FXINPUT_SetMultitap(false, false);
for (int i = 0; i < 2; i++)
FXINPUT_SetInput(i, Setting_PortDevice[i], &InputData[i]); // FXIT_GAMEPAD
PCFX_Power();
Ess.pixels = FrameBuffer;
Ess.pitch32 = 1024;
Ess.LineWidths = LineWidths;
Ess.SoundBufMaxSize = 2048;
return true;
}
static int ActiveDisk;
static uint32_t PrevConsoleButtons;
static void Blit(MyFrameInfo &f)
{
// two widths to deal with: 256 and "341" (which can be 256, 341, or 1024 wide depending on settings)
// two heights: 240 and 480, but watch out for scanlinestart / scanline end
// in pixel pro mode, 341 width is forced to 1024. we upsize 256 to 1024 as well, and double 240 tall
const uint32_t *src = FrameBuffer;
uint32_t *dst = f.VideoBuffer;
const int srcp = 1024;
src += Ess.y * srcp;
if (Setting_PixelPro)
{
f.Width = 1024;
f.Height = Ess.h;
const int dstp = 1024;
if (Ess.h > 240) // interlace
{
if (Ess.w == 256)
{
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp)
{
for (int i = 0; i < 256; i++)
{
auto c = src[i];
dst[i * 4 + 0] = c;
dst[i * 4 + 1] = c;
dst[i * 4 + 2] = c;
dst[i * 4 + 3] = c;
}
}
}
else
{
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp)
{
memcpy(dst, src, LineWidths[j + Ess.y] * sizeof(uint32_t));
}
}
}
else // progressive: line double
{
f.Height *= 2;
if (Ess.w == 256)
{
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp * 2)
{
for (int i = 0; i < 256; i++)
{
auto c = src[i];
dst[i * 4 + 0] = c;
dst[i * 4 + 1] = c;
dst[i * 4 + 2] = c;
dst[i * 4 + 3] = c;
}
memcpy(dst + dstp, dst, 4096);
}
}
else
{
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp * 2)
{
memcpy(dst, src, 4096);
memcpy(dst + dstp, src, 4096);
}
}
}
}
else
{
f.Width = Ess.w;
f.Height = Ess.h;
const int dstp = Ess.w;
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp)
{
memcpy(dst, src, LineWidths[j + Ess.y] * sizeof(uint32_t));
}
}
}
EXPORT void FrameAdvance(MyFrameInfo &f)
{
for (int i = 0; i < 2; i++)
InputData[i] = f.Buttons[i];
Lagged = true;
uint32_t ConsoleButtons = f.Buttons[2];
int NewActiveDisk = ActiveDisk;
#define ROSE(n) ((ConsoleButtons & 1 << (n)) > (PrevConsoleButtons & 1 << (n)))
if (ROSE(0))
PCFX_Power();
if (ROSE(1))
PCFX_Reset();
if (ROSE(2))
NewActiveDisk--;
if (ROSE(3))
NewActiveDisk++;
#undef ROSE
NewActiveDisk = std::max(NewActiveDisk, -1);
NewActiveDisk = std::min<int>(NewActiveDisk, CDInterfaces.size() - 1);
if (NewActiveDisk != ActiveDisk)
SCSICD_SetDisc(NewActiveDisk == -1, NewActiveDisk == -1 ? nullptr : CDInterfaces[NewActiveDisk]);
ActiveDisk = NewActiveDisk;
PrevConsoleButtons = ConsoleButtons;
Ess.SoundBuf = f.SoundBuffer;
Emulate(&Ess);
f.Cycles = Ess.MasterCycles;
f.Samples = Ess.SoundBufSize;
f.Lagged = Lagged;
Blit(f);
}
EXPORT void GetMemoryAreas(MemoryArea *m)
{
m[0].Data = BackupRAM;
m[0].Name = "Backup RAM";
m[0].Size = sizeof(BackupRAM);
m[0].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_SAVERAMMABLE;
m[1].Data = ExBackupRAM;
m[1].Name = "Extra Backup RAM";
m[1].Size = sizeof(ExBackupRAM);
m[1].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_SAVERAMMABLE;
m[2].Data = BIOSROM;
m[2].Name = "BIOS ROM";
m[2].Size = 1024 * 1024;
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE4;
m[3].Data = RAM;
m[3].Name = "Main RAM";
m[3].Size = 2 * 1024 * 1024;
m[3].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_PRIMARY;
// m[4].Data = FXSCSIROM;
// m[4].Name = "Scsi Rom";
// m[4].Size = 512 * 1024;
// m[4].Flags = MEMORYAREA_FLAGS_WORDSIZE4;
for (int i = 0; i < 2; i++)
{
m[i + 5].Data = fx_vdc_chips[i]->GetVramPointer();
m[i + 5].Name = i == 0 ? "VDC A VRAM" : "VDC B VRAM";
m[i + 5].Size = fx_vdc_chips[i]->GetVramByteSize();
m[i + 5].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE2;
}
}
EXPORT void EnableLayers(int mask)
{
// BG0 = 0
// BG1
// BG2
// BG3
// VDC-A BG
// VDC-A SPR
// VDC-B BG
// VDC-B SPR
// RAINBOW
KING_SetLayerEnableMask(mask);
}
EXPORT void SetInputCallback(void (*callback)())
{
InputCallback = callback;
}
// settings
ECL_SEALED int Setting_HighDotclockWidth = 341;
ECL_SEALED int Setting_CdSpeed = 2;
ECL_SEALED int Setting_SlStart = 4;
ECL_SEALED int Setting_SlEnd = 235;
ECL_SEALED double Setting_ResampRateError = 0.0000009;
ECL_SEALED int Setting_ResampQuality = 3;
ECL_SEALED int Setting_CpuEmulation = 2; // 0 = fast, 1 = accurate, 2 = auto
ECL_SEALED bool Setting_NoSpriteLimit;
ECL_SEALED bool Setting_AdpcmBuggy = false;
ECL_SEALED bool Setting_AdpcmNoClicks = true;
ECL_SEALED bool Setting_ChromaInterpolate = false;
ECL_SEALED int Setting_PortDevice[2];
ECL_SEALED bool Setting_PixelPro;
struct FrontendSettings
{
int32_t AdpcmEmulateBuggyCodec;
int32_t AdpcmSuppressChannelResetClicks;
int32_t HiResEmulation;
int32_t DisableSpriteLimit;
int32_t ChromaInterpolation;
int32_t ScanlineStart;
int32_t ScanlineEnd;
int32_t CdSpeed;
int32_t CpuEmulation;
int32_t Port1;
int32_t Port2;
int32_t PixelPro;
};
EXPORT void PutSettingsBeforeInit(const FrontendSettings &s)
{
Setting_AdpcmBuggy = s.AdpcmEmulateBuggyCodec;
Setting_AdpcmNoClicks = s.AdpcmSuppressChannelResetClicks;
Setting_HighDotclockWidth = s.PixelPro ? 1024 : s.HiResEmulation;
Setting_NoSpriteLimit = s.DisableSpriteLimit;
Setting_ChromaInterpolate = s.ChromaInterpolation;
Setting_SlStart = s.ScanlineStart;
Setting_SlEnd = s.ScanlineEnd;
Setting_CdSpeed = s.CdSpeed;
Setting_CpuEmulation = s.CpuEmulation;
Setting_PortDevice[0] = s.Port1;
Setting_PortDevice[1] = s.Port2;
Setting_PixelPro = s.PixelPro;
}
/*MDFNGI EmulatedPCFX =
{
FXINPUT_SetInput,
SetMedia,
DoSimpleCommand,
NULL,
PCFXSettings,
MDFN_MASTERCLOCK_FIXED(PCFX_MASTER_CLOCK),
0,
TRUE, // Multires possible?
288, // Nominal width
240, // Nominal height
1024, // Framebuffer width
512, // Framebuffer height
};*/
int main()
{
return 0;
}

View File

@ -1,67 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* pcfx.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PCFX_PCFX_H
#define __PCFX_PCFX_H
#include "defs.h"
#include "v810/v810_cpu.h"
#include "huc6270/vdc.h"
namespace MDFN_IEN_PCFX
{
#define PCFX_MASTER_CLOCK 21477272.72
#if 0
#define FXDBG(format, ...) MDFN_DebugPrint(format, ## __VA_ARGS__)
#else
#define FXDBG(format, ...) ((void)0)
#endif
extern V810 PCFX_V810;
uint8 MDFN_FASTCALL mem_peekbyte(const v810_timestamp_t timestamp, const uint32 A);
uint16 MDFN_FASTCALL mem_peekhword(const v810_timestamp_t timestamp, const uint32 A);
int32 MDFN_FASTCALL pcfx_event_handler(const v810_timestamp_t timestamp);
extern VDC *fx_vdc_chips[2];
#define REGSETHW(_reg, _data, _msh) { _reg &= 0xFFFF << (_msh ? 0 : 16); _reg |= _data << (_msh ? 16 : 0); }
#define REGGETHW(_reg, _msh) ((_reg >> (_msh ? 16 : 0)) & 0xFFFF)
enum
{
PCFX_EVENT_PAD = 0,
PCFX_EVENT_TIMER,
PCFX_EVENT_KING,
PCFX_EVENT_ADPCM
};
#define PCFX_EVENT_NONONO 0x7fffffff
void PCFX_SetEvent(const int type, const v810_timestamp_t next_timestamp);
}
#endif

View File

@ -1,819 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* rainbow.cpp:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
** MJPEG-like decoder based on the algorithm and Huffman data tables provided by David Michel
** of MagicEngine and MagicEngine-FX.
*/
#include "pcfx.h"
#include "rainbow.h"
#include "king.h"
#include "interrupt.h"
#include "jrevdct.h"
namespace MDFN_IEN_PCFX
{
static bool ChromaIP; // Bilinearly interpolate chroma channel
/* Y = luminance/luma, UV = chrominance/chroma */
struct HuffmanQuickLUTPair
{
uint8 val;
uint8 bitc; // Bit count for the code.
};
static const uint8 zigzag[63] =
{
0x01, 0x08, 0x10, 0x09, 0x02, 0x03, 0x0A, 0x11,
0x18, 0x20, 0x19, 0x12, 0x0B, 0x04, 0x05, 0x0C,
0x13, 0x1A, 0x21, 0x28, 0x30, 0x29, 0x22, 0x1B,
0x14, 0x0D, 0x06, 0x07, 0x0E, 0x15, 0x1C, 0x23,
0x2A, 0x31, 0x38, 0x39, 0x32, 0x2B, 0x24, 0x1D,
0x16, 0x0F, 0x17, 0x1E, 0x25, 0x2C, 0x33, 0x3A,
0x3B, 0x34, 0x2D, 0x26, 0x1F, 0x27, 0x2E, 0x35,
0x3C, 0x3D, 0x36, 0x2F, 0x37, 0x3E, 0x3F};
static const HuffmanQuickLUTPair ac_y_qlut[1 << 12] =
{
#include "rainbow_acy.inc"
};
static const HuffmanQuickLUTPair ac_uv_qlut[1 << 12] =
{
#include "rainbow_acuv.inc"
};
static const HuffmanQuickLUTPair dc_y_qlut[1 << 9] =
{
#include "rainbow_dcy.inc"
};
static const HuffmanQuickLUTPair dc_uv_qlut[1 << 8] =
{
#include "rainbow_dcuv.inc"
};
static uint8 *DecodeBuffer[2] = {NULL, NULL};
static int32 DecodeFormat[2]; // The format each buffer is in(-1 = invalid, 0 = palettized 8-bit, 1 = YUV)
static uint32 QuantTables[2][64], QuantTablesBase[2][64]; // 0 = Y, 1 = UV
static uint32 DecodeBufferWhichRead;
static int32 RasterReadPos;
static uint16 Control;
static uint16 NullRunY, NullRunU, NullRunV, HSync;
static uint16 HScroll;
static uint32 bits_buffer;
static uint32 bits_buffered_bits;
static int32 bits_bytes_left;
static void InitBits(int32 bcount)
{
bits_bytes_left = bcount;
bits_buffer = 0;
bits_buffered_bits = 0;
}
static INLINE uint8 FetchWidgywabbit(void)
{
if (bits_bytes_left <= 0)
return (0);
uint8 ret = KING_RB_Fetch();
if (ret == 0xFF)
KING_RB_Fetch();
bits_bytes_left--;
return (ret);
}
enum
{
MDFNBITS_PEEK = 1,
MDFNBITS_FUNNYSIGN = 2,
};
static INLINE uint32 GetBits(const unsigned int count, const unsigned int how = 0)
{
uint32 ret;
while (bits_buffered_bits < count)
{
bits_buffer <<= 8;
bits_buffer |= FetchWidgywabbit();
bits_buffered_bits += 8;
}
ret = (bits_buffer >> (bits_buffered_bits - count)) & ((1 << count) - 1);
if (!(how & MDFNBITS_PEEK))
bits_buffered_bits -= count;
if ((how & MDFNBITS_FUNNYSIGN) && count)
{
if (ret < (1U << (count - 1)))
ret += 1 - (1 << count);
}
return (ret);
}
// Note: SkipBits is intended to be called right after GetBits() with "how" MDFNBITS_PEEK,
// and the count pass to SkipBits must be less than or equal to the count passed to GetBits().
static INLINE void SkipBits(const unsigned int count)
{
bits_buffered_bits -= count;
}
static uint32 HappyColor; // Cached, calculated from null run yuv registers;
static void CalcHappyColor(void)
{
uint8 y_c = (int16)NullRunY + 0x80;
uint8 u_c = (int16)NullRunU + 0x80;
uint8 v_c = (int16)NullRunV + 0x80;
HappyColor = (y_c << 16) | (u_c << 8) | (v_c << 0);
}
static uint32 get_ac_coeff(const HuffmanQuickLUTPair *table, int32 *zeroes)
{
unsigned int numbits;
uint32 rawbits;
uint32 code;
rawbits = GetBits(12, MDFNBITS_PEEK);
code = table[rawbits].val;
SkipBits(table[rawbits].bitc);
numbits = code & 0xF;
*zeroes = code >> 4;
return (GetBits(numbits, MDFNBITS_FUNNYSIGN));
}
static uint32 get_dc_coeff(const HuffmanQuickLUTPair *table, int32 *zeroes, int maxbits)
{
uint32 code;
for (;;)
{
uint32 rawbits;
rawbits = GetBits(maxbits, MDFNBITS_PEEK);
code = table[rawbits].val;
SkipBits(table[rawbits].bitc);
if (code < 0xF)
{
*zeroes = 0;
return (GetBits(code, MDFNBITS_FUNNYSIGN));
}
else if (code == 0xF)
{
get_ac_coeff(ac_y_qlut, zeroes);
(*zeroes)++;
return (0);
}
else if (code >= 0x10)
{
code -= 0x10;
for (int i = 0; i < 64; i++)
{
// Y
uint32 coeff = (QuantTablesBase[0][i] * code) >> 2;
if (coeff < 1)
coeff = 1;
else if (coeff > 0xFE)
coeff = 0xFE;
QuantTables[0][i] = coeff;
// UV
if (i)
coeff = (QuantTablesBase[1][i] * code) >> 2;
else
coeff = (QuantTablesBase[1][i]) >> 2;
if (coeff < 1)
coeff = 1;
else if (coeff > 0xFE)
coeff = 0xFE;
QuantTables[1][i] = coeff;
}
}
}
}
static INLINE uint32 get_dc_y_coeff(int32 *zeroes)
{
return (get_dc_coeff(dc_y_qlut, zeroes, 9));
}
static uint32 get_dc_uv_coeff(void)
{
const HuffmanQuickLUTPair *table = dc_uv_qlut;
uint32 code;
uint32 rawbits = GetBits(8, MDFNBITS_PEEK);
code = table[rawbits].val;
SkipBits(table[rawbits].bitc);
return (GetBits(code, MDFNBITS_FUNNYSIGN));
}
static void decode(int32 *dct, const uint32 *QuantTable, const int32 dc, const HuffmanQuickLUTPair *table)
{
int32 coeff;
int zeroes;
int count;
int index;
dct[0] = (int16)(QuantTable[0] * dc);
count = 0;
do
{
coeff = get_ac_coeff(table, &zeroes);
if (!coeff)
{
if (!zeroes)
{
while (count < 63)
{
dct[zigzag[count++]] = 0;
}
break;
}
else if (zeroes == 1)
zeroes = 0xF;
}
while (zeroes-- && count < 63)
{
dct[zigzag[count++]] = 0;
}
zeroes = 0;
if (count < 63)
{
index = zigzag[count++];
dct[index] = (int16)(QuantTable[index] * coeff);
}
} while (count < 63);
}
#ifdef WANT_DEBUGGER
uint32 RAINBOW_GetRegister(const unsigned int id, char *special, const uint32 special_len)
{
uint32 value = 0xDEADBEEF;
if (id == RAINBOW_GSREG_RSCRLL)
value = HScroll;
else if (id == RAINBOW_GSREG_RCTRL)
value = Control;
else if (id == RAINBOW_GSREG_RNRY)
value = NullRunY;
else if (id == RAINBOW_GSREG_RNRU)
value = NullRunU;
else if (id == RAINBOW_GSREG_RNRV)
value = NullRunV;
else if (id == RAINBOW_GSREG_RHSYNC)
value = HSync;
return (value);
}
void RAINBOW_SetRegister(const unsigned int id, uint32 value)
{
if (id == RAINBOW_GSREG_RSCRLL)
HScroll = value & 0x1FF;
else if (id == RAINBOW_GSREG_RCTRL)
Control = value;
else if (id == RAINBOW_GSREG_RNRY)
NullRunY = value;
else if (id == RAINBOW_GSREG_RNRU)
NullRunU = value;
else if (id == RAINBOW_GSREG_RNRV)
NullRunV = value;
}
#endif
static uint32 LastLine[256];
static bool FirstDecode;
static bool GarbageData;
void RAINBOW_Init(bool arg_ChromaIP)
{
ChromaIP = arg_ChromaIP;
for (int i = 0; i < 2; i++)
{
DecodeBuffer[i] = new uint8[0x2000 * 4];
memset(DecodeBuffer[i], 0, 0x2000 * 4);
}
DecodeFormat[0] = DecodeFormat[1] = -1;
DecodeBufferWhichRead = 0;
GarbageData = FALSE;
FirstDecode = TRUE;
RasterReadPos = 0;
}
// RAINBOW base I/O port address: 0x200
#define REGSETBOFW(_reg, _data, _wb) \
{ \
(_reg) &= ~(0xFF << ((_wb)*8)); \
(_reg) |= (_data) << ((_wb)*8); \
}
#define REGSETBOFH REGSETBOFW
// The horizontal scroll register is set up kind of weird...D0-D7 of writes to $200 set the lower byte, D0-D7 of writes to $202 set the upper byte
void RAINBOW_Write8(uint32 A, uint8 V)
{
//printf("RAINBOW Wr8: %08x %02x\n", A, V);
switch (A & 0x1C)
{
case 0x00:
REGSETBOFH(HScroll, V, (A & 0x2) >> 1);
HScroll &= 0x1FF;
break;
case 0x04:
REGSETBOFH(Control, V, A & 0x3);
break;
case 0x08:
REGSETBOFH(NullRunY, V, A & 0x3);
CalcHappyColor();
break;
case 0x0C:
REGSETBOFH(NullRunU, V, A & 0x3);
CalcHappyColor();
break;
case 0x10:
REGSETBOFH(NullRunV, V, A & 0x3);
CalcHappyColor();
break;
case 0x14:
REGSETBOFH(HSync, V, A & 0x3);
break;
}
}
void RAINBOW_Write16(uint32 A, uint16 V)
{
int msh = A & 0x2;
//printf("RAINBOW Wr16: %08x %04x\n", A, V);
switch (A & 0x1C)
{
case 0x00:
REGSETBOFH(HScroll, V & 0xFF, (A & 0x2) >> 1);
HScroll &= 0x1FF;
break;
case 0x04:
REGSETHW(Control, V, msh);
break;
case 0x08:
REGSETHW(NullRunY, V, msh);
CalcHappyColor();
break;
case 0x0C:
REGSETHW(NullRunU, V, msh);
CalcHappyColor();
break;
case 0x10:
REGSETHW(NullRunV, V, msh);
CalcHappyColor();
break;
case 0x14:
REGSETHW(HSync, V, msh);
break;
}
}
void RAINBOW_ForceTransferReset(void)
{
RasterReadPos = 0;
DecodeFormat[0] = DecodeFormat[1] = -1;
}
void RAINBOW_SwapBuffers(void)
{
DecodeBufferWhichRead ^= 1;
RasterReadPos = 0;
}
void RAINBOW_DecodeBlock(bool arg_FirstDecode, bool Skip)
{
uint8 block_type;
int32 block_size;
int icount;
int which_buffer = DecodeBufferWhichRead ^ 1;
if (!(Control & 0x01))
{
puts("Rainbow decode when disabled!!");
return;
}
if (arg_FirstDecode)
{
FirstDecode = TRUE;
GarbageData = FALSE;
}
if (GarbageData)
icount = 0;
else
icount = 0x200;
do
{
do
{
while (KING_RB_Fetch() != 0xFF && icount > 0)
icount--;
block_type = KING_RB_Fetch();
//if(icount > 0 && block_type != 0xF0 && block_type != 0xF1 && block_type != 0xF2 && block_type != 0xF3 && block_type != 0xF8 && block_type != 0xFF)
//if(icount > 0 && block_type == 0x11)
// printf("%02x\n", block_type);
icount--;
} while (block_type != 0xF0 && block_type != 0xF1 && block_type != 0xF2 && block_type != 0xF3 && block_type != 0xF8 && block_type != 0xFF && icount > 0);
{
uint16 tmp;
tmp = KING_RB_Fetch() << 8;
tmp |= KING_RB_Fetch() << 0;
block_size = (int16)tmp;
}
block_size -= 2;
if (block_type == 0xFF && block_size <= 0)
for (int i = 0; i < 128; i++, icount--)
KING_RB_Fetch();
//fprintf(stderr, "Block: %d\n", block_size);
} while (block_size <= 0 && icount > 0);
//if(!GarbageData && icount < 500)
//{
// FXDBG("Partial garbage data. %d", icount);
//}
//printf("%d\n", icount);
if (icount <= 0)
{
FXDBG("Garbage data.");
GarbageData = TRUE;
//printf("Dooom: %d\n");
DecodeFormat[which_buffer] = 0;
memset(DecodeBuffer[which_buffer], 0, 0x2000);
goto BufferNoDecode;
}
if (block_type == 0xf8 || block_type == 0xff)
DecodeFormat[which_buffer] = 1;
else
DecodeFormat[which_buffer] = 0;
if (block_type == 0xF8 || block_type == 0xFF)
{
if (block_type == 0xFF)
{
for (int q = 0; q < 2; q++)
for (int i = 0; i < 64; i++)
{
uint8 meow = KING_RB_Fetch();
QuantTables[q][i] = meow;
QuantTablesBase[q][i] = meow;
}
block_size -= 128;
}
InitBits(block_size);
int32 dc_y = 0, dc_u = 0, dc_v = 0;
uint32 *dest_base = (uint32 *)DecodeBuffer[which_buffer];
for (int column = 0; column < 16; column++)
{
uint32 *dest_base_column = &dest_base[column * 16];
int zeroes = 0;
dc_y += get_dc_y_coeff(&zeroes);
if (zeroes) // If set, clear the number of columns
{
do
{
if (column < 16)
{
dest_base_column = &dest_base[column * 16];
for (int y = 0; y < 16; y++)
for (int x = 0; x < 16; x++)
dest_base_column[y * 256 + x] = HappyColor;
}
column++;
zeroes--;
} while (zeroes);
column--; // Fix for the column autoincrement in the while(zeroes) loop
dc_y = dc_u = dc_v = 0;
}
else
{
int32 dct_y[256];
int32 dct_u[64];
int32 dct_v[64];
// Y/Luma, 16x16 components
// ---------
// | A | C |
// |-------|
// | B | D |
// ---------
// A (0, 0)
decode(&dct_y[0x00], QuantTables[0], dc_y, ac_y_qlut);
// B (0, 1)
dc_y += get_dc_y_coeff(&zeroes);
decode(&dct_y[0x40], QuantTables[0], dc_y, ac_y_qlut);
// C (1, 0)
dc_y += get_dc_y_coeff(&zeroes);
decode(&dct_y[0x80], QuantTables[0], dc_y, ac_y_qlut);
// D (1, 1)
dc_y += get_dc_y_coeff(&zeroes);
decode(&dct_y[0xC0], QuantTables[0], dc_y, ac_y_qlut);
// U, 8x8 components
dc_u += get_dc_uv_coeff();
decode(&dct_u[0x00], QuantTables[1], dc_u, ac_uv_qlut);
// V, 8x8 components
dc_v += get_dc_uv_coeff();
decode(&dct_v[0x00], QuantTables[1], dc_v, ac_uv_qlut);
if (Skip)
continue;
j_rev_dct(&dct_y[0x00]);
j_rev_dct(&dct_y[0x40]);
j_rev_dct(&dct_y[0x80]);
j_rev_dct(&dct_y[0xC0]);
j_rev_dct(&dct_u[0x00]);
j_rev_dct(&dct_v[0x00]);
for (int y = 0; y < 16; y++)
for (int x = 0; x < 16; x++)
dest_base_column[y * 256 + x] = clamp_to_u8(dct_y[y * 8 + (x & 0x7) + ((x & 0x8) << 4)] + 0x80) << 16;
if (!ChromaIP)
{
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
uint32 component_uv = (clamp_to_u8(dct_u[y * 8 + x] + 0x80) << 8) | clamp_to_u8(dct_v[y * 8 + x] + 0x80);
dest_base_column[y * 512 + (256 * 0) + x * 2 + 0] |= component_uv;
dest_base_column[y * 512 + (256 * 0) + x * 2 + 1] |= component_uv;
dest_base_column[y * 512 + (256 * 1) + x * 2 + 0] |= component_uv;
dest_base_column[y * 512 + (256 * 1) + x * 2 + 1] |= component_uv;
}
}
}
else
{
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
uint32 component_uv = (clamp_to_u8(dct_u[y * 8 + x] + 0x80) << 8) | clamp_to_u8(dct_v[y * 8 + x] + 0x80);
dest_base_column[y * 512 + (256 * 1) + x * 2 + 0] |= component_uv;
}
}
}
}
}
// Do bilinear interpolation on the chroma channels:
if (!Skip && ChromaIP)
{
for (int y = 0; y < 16; y += 2)
{
uint32 *linebase = &dest_base[y * 256];
uint32 *linebase1 = &dest_base[(y + 1) * 256];
for (int x = 0; x < 254; x += 2)
{
unsigned int u, v;
u = (((linebase1[x] >> 8) & 0xFF) + ((linebase1[x + 2] >> 8) & 0xFF)) >> 1;
v = (((linebase1[x] >> 0) & 0xFF) + ((linebase1[x + 2] >> 0) & 0xFF)) >> 1;
linebase1[x + 1] = (linebase1[x + 1] & ~0xFFFF) | (u << 8) | v;
}
linebase1[0xFF] = (linebase1[0xFF] & ~0xFFFF) | (linebase1[0xFE] & 0xFFFF);
if (FirstDecode)
{
for (int x = 0; x < 256; x++)
linebase[x] = (linebase[x] & ~0xFFFF) | (linebase1[x] & 0xFFFF);
FirstDecode = 0;
}
else
for (int x = 0; x < 256; x++)
{
unsigned int u, v;
u = (((LastLine[x] >> 8) & 0xFF) + ((linebase1[x] >> 8) & 0xFF)) >> 1;
v = (((LastLine[x] >> 0) & 0xFF) + ((linebase1[x] >> 0) & 0xFF)) >> 1;
linebase[x] = (linebase[x] & ~0xFFFF) | (u << 8) | v;
}
memcpy(LastLine, linebase1, 256 * 4);
}
} // End chroma interpolation
} // end jpeg-like decoding
else
{
// Earlier code confines the set to F0,F1,F2, and F3.
// F0 = (4, 0xF), F1 = (3, 0x7), F2 = (0x2, 0x3), F3 = 0x1, 0x1)
const unsigned int plt_shift = 4 - (block_type & 0x3);
const unsigned int crl_mask = (1 << plt_shift) - 1;
int x = 0;
while (block_size > 0)
{
uint8 boot;
unsigned int rle_count;
boot = KING_RB_Fetch();
block_size--;
if (boot == 0xFF)
{
KING_RB_Fetch();
block_size--;
}
if (!(boot & crl_mask)) // Expand mode?
{
rle_count = KING_RB_Fetch();
block_size--;
if (rle_count == 0xFF)
{
KING_RB_Fetch();
block_size--;
}
rle_count++;
}
else
rle_count = boot & crl_mask;
for (unsigned int i = 0; i < rle_count; i++)
{
if (x >= 0x2000)
{
//puts("Oops");
break; // Don't overflow our decode buffer!
}
DecodeBuffer[which_buffer][x] = (boot >> plt_shift);
x++;
}
}
} // end RLE decoding
//for(int i = 0; i < 8 + block_size; i++)
// KING_RB_Fetch();
BufferNoDecode:;
}
void KING_Moo(void);
// NOTE: layer_or and palette_ptr are optimizations, the real RAINBOW chip knows not of such things.
int RAINBOW_FetchRaster(uint32 *linebuffer, uint32 layer_or, uint32 *palette_ptr)
{
int ret;
ret = DecodeFormat[DecodeBufferWhichRead];
if (linebuffer)
{
linebuffer = MDFN_ASSUME_ALIGNED(linebuffer, 8);
//
if (DecodeFormat[DecodeBufferWhichRead] == -1) // None
{
MDFN_FastArraySet(linebuffer, 0, 256);
}
else if (DecodeFormat[DecodeBufferWhichRead] == 1) // YUV
{
uint32 *in_ptr = (uint32 *)&DecodeBuffer[DecodeBufferWhichRead][RasterReadPos * 256 * 4];
if (Control & 0x2) // Endless scroll mode:
{
uint8 tmpss = HScroll;
for (int x = 0; x < 256; x++)
{
linebuffer[x] = in_ptr[tmpss] | layer_or;
tmpss++;
}
}
else // Non-endless
{
uint16 tmpss = HScroll & 0x1FF;
for (int x = 0; x < 256; x++)
{
linebuffer[x] = (tmpss < 256) ? (in_ptr[tmpss] | layer_or) : 0;
tmpss = (tmpss + 1) & 0x1FF;
}
}
MDFN_FastArraySet(in_ptr, 0, 256);
}
else if (DecodeFormat[DecodeBufferWhichRead] == 0) // Palette
{
uint8 *in_ptr = &DecodeBuffer[DecodeBufferWhichRead][RasterReadPos * 256];
if (Control & 0x2) // Endless scroll mode:
{
uint8 tmpss = HScroll;
for (int x = 0; x < 256; x++)
{
linebuffer[x] = in_ptr[tmpss] ? (palette_ptr[in_ptr[tmpss]] | layer_or) : 0;
tmpss++;
}
}
else // Non-endless
{
uint16 tmpss = HScroll & 0x1FF;
for (int x = 0; x < 256; x++)
{
linebuffer[x] = (tmpss < 256 && in_ptr[tmpss]) ? (palette_ptr[in_ptr[tmpss]] | layer_or) : 0;
tmpss = (tmpss + 1) & 0x1FF;
}
}
//MDFN_FastU32MemsetM8((uint32 *)in_ptr, 0, 256 / 4);
}
}
RasterReadPos = (RasterReadPos + 1) & 0xF;
if (!RasterReadPos)
DecodeFormat[DecodeBufferWhichRead] = -1; // Invalidate this buffer.
//printf("Fetch: %d, buffer: %d\n", RasterReadPos, DecodeBufferWhichRead);
return (ret);
}
void RAINBOW_Reset(void)
{
Control = 0;
NullRunY = NullRunU = NullRunV = 0;
HScroll = 0;
RasterReadPos = 0;
DecodeBufferWhichRead = 0;
memset(QuantTables, 0, sizeof(QuantTables));
memset(QuantTablesBase, 0, sizeof(QuantTablesBase));
DecodeFormat[0] = DecodeFormat[1] = -1;
CalcHappyColor();
}
}

View File

@ -1,56 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* rainbow.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PCFX_RAINBOW_H
#define __PCFX_RAINBOW_H
namespace MDFN_IEN_PCFX
{
void RAINBOW_Write8(uint32 A, uint8 V);
void RAINBOW_Write16(uint32 A, uint16 V);
void RAINBOW_ForceTransferReset(void);
void RAINBOW_SwapBuffers(void);
void RAINBOW_DecodeBlock(bool arg_FirstDecode, bool Skip);
int RAINBOW_FetchRaster(uint32 *, uint32 layer_or, uint32 *palette_ptr);
void RAINBOW_Init(bool arg_ChromaIP) MDFN_COLD;
void RAINBOW_Reset(void) MDFN_COLD;
#ifdef WANT_DEBUGGER
enum
{
RAINBOW_GSREG_RSCRLL,
RAINBOW_GSREG_RCTRL,
RAINBOW_GSREG_RNRY,
RAINBOW_GSREG_RNRU,
RAINBOW_GSREG_RNRV,
RAINBOW_GSREG_RHSYNC,
};
uint32 RAINBOW_GetRegister(const unsigned int id, char* special, const uint32 special_len);
void RAINBOW_SetRegister(const unsigned int id, uint32 value);
#endif
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,256 +0,0 @@
/* 00 */ { 0x00, 0x02 },
/* 01 */ { 0x00, 0x02 },
/* 02 */ { 0x00, 0x02 },
/* 03 */ { 0x00, 0x02 },
/* 04 */ { 0x00, 0x02 },
/* 05 */ { 0x00, 0x02 },
/* 06 */ { 0x00, 0x02 },
/* 07 */ { 0x00, 0x02 },
/* 08 */ { 0x00, 0x02 },
/* 09 */ { 0x00, 0x02 },
/* 0a */ { 0x00, 0x02 },
/* 0b */ { 0x00, 0x02 },
/* 0c */ { 0x00, 0x02 },
/* 0d */ { 0x00, 0x02 },
/* 0e */ { 0x00, 0x02 },
/* 0f */ { 0x00, 0x02 },
/* 10 */ { 0x00, 0x02 },
/* 11 */ { 0x00, 0x02 },
/* 12 */ { 0x00, 0x02 },
/* 13 */ { 0x00, 0x02 },
/* 14 */ { 0x00, 0x02 },
/* 15 */ { 0x00, 0x02 },
/* 16 */ { 0x00, 0x02 },
/* 17 */ { 0x00, 0x02 },
/* 18 */ { 0x00, 0x02 },
/* 19 */ { 0x00, 0x02 },
/* 1a */ { 0x00, 0x02 },
/* 1b */ { 0x00, 0x02 },
/* 1c */ { 0x00, 0x02 },
/* 1d */ { 0x00, 0x02 },
/* 1e */ { 0x00, 0x02 },
/* 1f */ { 0x00, 0x02 },
/* 20 */ { 0x00, 0x02 },
/* 21 */ { 0x00, 0x02 },
/* 22 */ { 0x00, 0x02 },
/* 23 */ { 0x00, 0x02 },
/* 24 */ { 0x00, 0x02 },
/* 25 */ { 0x00, 0x02 },
/* 26 */ { 0x00, 0x02 },
/* 27 */ { 0x00, 0x02 },
/* 28 */ { 0x00, 0x02 },
/* 29 */ { 0x00, 0x02 },
/* 2a */ { 0x00, 0x02 },
/* 2b */ { 0x00, 0x02 },
/* 2c */ { 0x00, 0x02 },
/* 2d */ { 0x00, 0x02 },
/* 2e */ { 0x00, 0x02 },
/* 2f */ { 0x00, 0x02 },
/* 30 */ { 0x00, 0x02 },
/* 31 */ { 0x00, 0x02 },
/* 32 */ { 0x00, 0x02 },
/* 33 */ { 0x00, 0x02 },
/* 34 */ { 0x00, 0x02 },
/* 35 */ { 0x00, 0x02 },
/* 36 */ { 0x00, 0x02 },
/* 37 */ { 0x00, 0x02 },
/* 38 */ { 0x00, 0x02 },
/* 39 */ { 0x00, 0x02 },
/* 3a */ { 0x00, 0x02 },
/* 3b */ { 0x00, 0x02 },
/* 3c */ { 0x00, 0x02 },
/* 3d */ { 0x00, 0x02 },
/* 3e */ { 0x00, 0x02 },
/* 3f */ { 0x00, 0x02 },
/* 40 */ { 0x01, 0x02 },
/* 41 */ { 0x01, 0x02 },
/* 42 */ { 0x01, 0x02 },
/* 43 */ { 0x01, 0x02 },
/* 44 */ { 0x01, 0x02 },
/* 45 */ { 0x01, 0x02 },
/* 46 */ { 0x01, 0x02 },
/* 47 */ { 0x01, 0x02 },
/* 48 */ { 0x01, 0x02 },
/* 49 */ { 0x01, 0x02 },
/* 4a */ { 0x01, 0x02 },
/* 4b */ { 0x01, 0x02 },
/* 4c */ { 0x01, 0x02 },
/* 4d */ { 0x01, 0x02 },
/* 4e */ { 0x01, 0x02 },
/* 4f */ { 0x01, 0x02 },
/* 50 */ { 0x01, 0x02 },
/* 51 */ { 0x01, 0x02 },
/* 52 */ { 0x01, 0x02 },
/* 53 */ { 0x01, 0x02 },
/* 54 */ { 0x01, 0x02 },
/* 55 */ { 0x01, 0x02 },
/* 56 */ { 0x01, 0x02 },
/* 57 */ { 0x01, 0x02 },
/* 58 */ { 0x01, 0x02 },
/* 59 */ { 0x01, 0x02 },
/* 5a */ { 0x01, 0x02 },
/* 5b */ { 0x01, 0x02 },
/* 5c */ { 0x01, 0x02 },
/* 5d */ { 0x01, 0x02 },
/* 5e */ { 0x01, 0x02 },
/* 5f */ { 0x01, 0x02 },
/* 60 */ { 0x01, 0x02 },
/* 61 */ { 0x01, 0x02 },
/* 62 */ { 0x01, 0x02 },
/* 63 */ { 0x01, 0x02 },
/* 64 */ { 0x01, 0x02 },
/* 65 */ { 0x01, 0x02 },
/* 66 */ { 0x01, 0x02 },
/* 67 */ { 0x01, 0x02 },
/* 68 */ { 0x01, 0x02 },
/* 69 */ { 0x01, 0x02 },
/* 6a */ { 0x01, 0x02 },
/* 6b */ { 0x01, 0x02 },
/* 6c */ { 0x01, 0x02 },
/* 6d */ { 0x01, 0x02 },
/* 6e */ { 0x01, 0x02 },
/* 6f */ { 0x01, 0x02 },
/* 70 */ { 0x01, 0x02 },
/* 71 */ { 0x01, 0x02 },
/* 72 */ { 0x01, 0x02 },
/* 73 */ { 0x01, 0x02 },
/* 74 */ { 0x01, 0x02 },
/* 75 */ { 0x01, 0x02 },
/* 76 */ { 0x01, 0x02 },
/* 77 */ { 0x01, 0x02 },
/* 78 */ { 0x01, 0x02 },
/* 79 */ { 0x01, 0x02 },
/* 7a */ { 0x01, 0x02 },
/* 7b */ { 0x01, 0x02 },
/* 7c */ { 0x01, 0x02 },
/* 7d */ { 0x01, 0x02 },
/* 7e */ { 0x01, 0x02 },
/* 7f */ { 0x01, 0x02 },
/* 80 */ { 0x02, 0x02 },
/* 81 */ { 0x02, 0x02 },
/* 82 */ { 0x02, 0x02 },
/* 83 */ { 0x02, 0x02 },
/* 84 */ { 0x02, 0x02 },
/* 85 */ { 0x02, 0x02 },
/* 86 */ { 0x02, 0x02 },
/* 87 */ { 0x02, 0x02 },
/* 88 */ { 0x02, 0x02 },
/* 89 */ { 0x02, 0x02 },
/* 8a */ { 0x02, 0x02 },
/* 8b */ { 0x02, 0x02 },
/* 8c */ { 0x02, 0x02 },
/* 8d */ { 0x02, 0x02 },
/* 8e */ { 0x02, 0x02 },
/* 8f */ { 0x02, 0x02 },
/* 90 */ { 0x02, 0x02 },
/* 91 */ { 0x02, 0x02 },
/* 92 */ { 0x02, 0x02 },
/* 93 */ { 0x02, 0x02 },
/* 94 */ { 0x02, 0x02 },
/* 95 */ { 0x02, 0x02 },
/* 96 */ { 0x02, 0x02 },
/* 97 */ { 0x02, 0x02 },
/* 98 */ { 0x02, 0x02 },
/* 99 */ { 0x02, 0x02 },
/* 9a */ { 0x02, 0x02 },
/* 9b */ { 0x02, 0x02 },
/* 9c */ { 0x02, 0x02 },
/* 9d */ { 0x02, 0x02 },
/* 9e */ { 0x02, 0x02 },
/* 9f */ { 0x02, 0x02 },
/* a0 */ { 0x02, 0x02 },
/* a1 */ { 0x02, 0x02 },
/* a2 */ { 0x02, 0x02 },
/* a3 */ { 0x02, 0x02 },
/* a4 */ { 0x02, 0x02 },
/* a5 */ { 0x02, 0x02 },
/* a6 */ { 0x02, 0x02 },
/* a7 */ { 0x02, 0x02 },
/* a8 */ { 0x02, 0x02 },
/* a9 */ { 0x02, 0x02 },
/* aa */ { 0x02, 0x02 },
/* ab */ { 0x02, 0x02 },
/* ac */ { 0x02, 0x02 },
/* ad */ { 0x02, 0x02 },
/* ae */ { 0x02, 0x02 },
/* af */ { 0x02, 0x02 },
/* b0 */ { 0x02, 0x02 },
/* b1 */ { 0x02, 0x02 },
/* b2 */ { 0x02, 0x02 },
/* b3 */ { 0x02, 0x02 },
/* b4 */ { 0x02, 0x02 },
/* b5 */ { 0x02, 0x02 },
/* b6 */ { 0x02, 0x02 },
/* b7 */ { 0x02, 0x02 },
/* b8 */ { 0x02, 0x02 },
/* b9 */ { 0x02, 0x02 },
/* ba */ { 0x02, 0x02 },
/* bb */ { 0x02, 0x02 },
/* bc */ { 0x02, 0x02 },
/* bd */ { 0x02, 0x02 },
/* be */ { 0x02, 0x02 },
/* bf */ { 0x02, 0x02 },
/* c0 */ { 0x03, 0x03 },
/* c1 */ { 0x03, 0x03 },
/* c2 */ { 0x03, 0x03 },
/* c3 */ { 0x03, 0x03 },
/* c4 */ { 0x03, 0x03 },
/* c5 */ { 0x03, 0x03 },
/* c6 */ { 0x03, 0x03 },
/* c7 */ { 0x03, 0x03 },
/* c8 */ { 0x03, 0x03 },
/* c9 */ { 0x03, 0x03 },
/* ca */ { 0x03, 0x03 },
/* cb */ { 0x03, 0x03 },
/* cc */ { 0x03, 0x03 },
/* cd */ { 0x03, 0x03 },
/* ce */ { 0x03, 0x03 },
/* cf */ { 0x03, 0x03 },
/* d0 */ { 0x03, 0x03 },
/* d1 */ { 0x03, 0x03 },
/* d2 */ { 0x03, 0x03 },
/* d3 */ { 0x03, 0x03 },
/* d4 */ { 0x03, 0x03 },
/* d5 */ { 0x03, 0x03 },
/* d6 */ { 0x03, 0x03 },
/* d7 */ { 0x03, 0x03 },
/* d8 */ { 0x03, 0x03 },
/* d9 */ { 0x03, 0x03 },
/* da */ { 0x03, 0x03 },
/* db */ { 0x03, 0x03 },
/* dc */ { 0x03, 0x03 },
/* dd */ { 0x03, 0x03 },
/* de */ { 0x03, 0x03 },
/* df */ { 0x03, 0x03 },
/* e0 */ { 0x04, 0x04 },
/* e1 */ { 0x04, 0x04 },
/* e2 */ { 0x04, 0x04 },
/* e3 */ { 0x04, 0x04 },
/* e4 */ { 0x04, 0x04 },
/* e5 */ { 0x04, 0x04 },
/* e6 */ { 0x04, 0x04 },
/* e7 */ { 0x04, 0x04 },
/* e8 */ { 0x04, 0x04 },
/* e9 */ { 0x04, 0x04 },
/* ea */ { 0x04, 0x04 },
/* eb */ { 0x04, 0x04 },
/* ec */ { 0x04, 0x04 },
/* ed */ { 0x04, 0x04 },
/* ee */ { 0x04, 0x04 },
/* ef */ { 0x04, 0x04 },
/* f0 */ { 0x05, 0x05 },
/* f1 */ { 0x05, 0x05 },
/* f2 */ { 0x05, 0x05 },
/* f3 */ { 0x05, 0x05 },
/* f4 */ { 0x05, 0x05 },
/* f5 */ { 0x05, 0x05 },
/* f6 */ { 0x05, 0x05 },
/* f7 */ { 0x05, 0x05 },
/* f8 */ { 0x06, 0x06 },
/* f9 */ { 0x06, 0x06 },
/* fa */ { 0x06, 0x06 },
/* fb */ { 0x06, 0x06 },
/* fc */ { 0x07, 0x07 },
/* fd */ { 0x07, 0x07 },
/* fe */ { 0x08, 0x08 },
/* ff */ { 0x09, 0x08 },

View File

@ -1,512 +0,0 @@
/* 000 */ { 0x00, 0x03 },
/* 001 */ { 0x00, 0x03 },
/* 002 */ { 0x00, 0x03 },
/* 003 */ { 0x00, 0x03 },
/* 004 */ { 0x00, 0x03 },
/* 005 */ { 0x00, 0x03 },
/* 006 */ { 0x00, 0x03 },
/* 007 */ { 0x00, 0x03 },
/* 008 */ { 0x00, 0x03 },
/* 009 */ { 0x00, 0x03 },
/* 00a */ { 0x00, 0x03 },
/* 00b */ { 0x00, 0x03 },
/* 00c */ { 0x00, 0x03 },
/* 00d */ { 0x00, 0x03 },
/* 00e */ { 0x00, 0x03 },
/* 00f */ { 0x00, 0x03 },
/* 010 */ { 0x00, 0x03 },
/* 011 */ { 0x00, 0x03 },
/* 012 */ { 0x00, 0x03 },
/* 013 */ { 0x00, 0x03 },
/* 014 */ { 0x00, 0x03 },
/* 015 */ { 0x00, 0x03 },
/* 016 */ { 0x00, 0x03 },
/* 017 */ { 0x00, 0x03 },
/* 018 */ { 0x00, 0x03 },
/* 019 */ { 0x00, 0x03 },
/* 01a */ { 0x00, 0x03 },
/* 01b */ { 0x00, 0x03 },
/* 01c */ { 0x00, 0x03 },
/* 01d */ { 0x00, 0x03 },
/* 01e */ { 0x00, 0x03 },
/* 01f */ { 0x00, 0x03 },
/* 020 */ { 0x00, 0x03 },
/* 021 */ { 0x00, 0x03 },
/* 022 */ { 0x00, 0x03 },
/* 023 */ { 0x00, 0x03 },
/* 024 */ { 0x00, 0x03 },
/* 025 */ { 0x00, 0x03 },
/* 026 */ { 0x00, 0x03 },
/* 027 */ { 0x00, 0x03 },
/* 028 */ { 0x00, 0x03 },
/* 029 */ { 0x00, 0x03 },
/* 02a */ { 0x00, 0x03 },
/* 02b */ { 0x00, 0x03 },
/* 02c */ { 0x00, 0x03 },
/* 02d */ { 0x00, 0x03 },
/* 02e */ { 0x00, 0x03 },
/* 02f */ { 0x00, 0x03 },
/* 030 */ { 0x00, 0x03 },
/* 031 */ { 0x00, 0x03 },
/* 032 */ { 0x00, 0x03 },
/* 033 */ { 0x00, 0x03 },
/* 034 */ { 0x00, 0x03 },
/* 035 */ { 0x00, 0x03 },
/* 036 */ { 0x00, 0x03 },
/* 037 */ { 0x00, 0x03 },
/* 038 */ { 0x00, 0x03 },
/* 039 */ { 0x00, 0x03 },
/* 03a */ { 0x00, 0x03 },
/* 03b */ { 0x00, 0x03 },
/* 03c */ { 0x00, 0x03 },
/* 03d */ { 0x00, 0x03 },
/* 03e */ { 0x00, 0x03 },
/* 03f */ { 0x00, 0x03 },
/* 040 */ { 0x02, 0x03 },
/* 041 */ { 0x02, 0x03 },
/* 042 */ { 0x02, 0x03 },
/* 043 */ { 0x02, 0x03 },
/* 044 */ { 0x02, 0x03 },
/* 045 */ { 0x02, 0x03 },
/* 046 */ { 0x02, 0x03 },
/* 047 */ { 0x02, 0x03 },
/* 048 */ { 0x02, 0x03 },
/* 049 */ { 0x02, 0x03 },
/* 04a */ { 0x02, 0x03 },
/* 04b */ { 0x02, 0x03 },
/* 04c */ { 0x02, 0x03 },
/* 04d */ { 0x02, 0x03 },
/* 04e */ { 0x02, 0x03 },
/* 04f */ { 0x02, 0x03 },
/* 050 */ { 0x02, 0x03 },
/* 051 */ { 0x02, 0x03 },
/* 052 */ { 0x02, 0x03 },
/* 053 */ { 0x02, 0x03 },
/* 054 */ { 0x02, 0x03 },
/* 055 */ { 0x02, 0x03 },
/* 056 */ { 0x02, 0x03 },
/* 057 */ { 0x02, 0x03 },
/* 058 */ { 0x02, 0x03 },
/* 059 */ { 0x02, 0x03 },
/* 05a */ { 0x02, 0x03 },
/* 05b */ { 0x02, 0x03 },
/* 05c */ { 0x02, 0x03 },
/* 05d */ { 0x02, 0x03 },
/* 05e */ { 0x02, 0x03 },
/* 05f */ { 0x02, 0x03 },
/* 060 */ { 0x02, 0x03 },
/* 061 */ { 0x02, 0x03 },
/* 062 */ { 0x02, 0x03 },
/* 063 */ { 0x02, 0x03 },
/* 064 */ { 0x02, 0x03 },
/* 065 */ { 0x02, 0x03 },
/* 066 */ { 0x02, 0x03 },
/* 067 */ { 0x02, 0x03 },
/* 068 */ { 0x02, 0x03 },
/* 069 */ { 0x02, 0x03 },
/* 06a */ { 0x02, 0x03 },
/* 06b */ { 0x02, 0x03 },
/* 06c */ { 0x02, 0x03 },
/* 06d */ { 0x02, 0x03 },
/* 06e */ { 0x02, 0x03 },
/* 06f */ { 0x02, 0x03 },
/* 070 */ { 0x02, 0x03 },
/* 071 */ { 0x02, 0x03 },
/* 072 */ { 0x02, 0x03 },
/* 073 */ { 0x02, 0x03 },
/* 074 */ { 0x02, 0x03 },
/* 075 */ { 0x02, 0x03 },
/* 076 */ { 0x02, 0x03 },
/* 077 */ { 0x02, 0x03 },
/* 078 */ { 0x02, 0x03 },
/* 079 */ { 0x02, 0x03 },
/* 07a */ { 0x02, 0x03 },
/* 07b */ { 0x02, 0x03 },
/* 07c */ { 0x02, 0x03 },
/* 07d */ { 0x02, 0x03 },
/* 07e */ { 0x02, 0x03 },
/* 07f */ { 0x02, 0x03 },
/* 080 */ { 0x03, 0x03 },
/* 081 */ { 0x03, 0x03 },
/* 082 */ { 0x03, 0x03 },
/* 083 */ { 0x03, 0x03 },
/* 084 */ { 0x03, 0x03 },
/* 085 */ { 0x03, 0x03 },
/* 086 */ { 0x03, 0x03 },
/* 087 */ { 0x03, 0x03 },
/* 088 */ { 0x03, 0x03 },
/* 089 */ { 0x03, 0x03 },
/* 08a */ { 0x03, 0x03 },
/* 08b */ { 0x03, 0x03 },
/* 08c */ { 0x03, 0x03 },
/* 08d */ { 0x03, 0x03 },
/* 08e */ { 0x03, 0x03 },
/* 08f */ { 0x03, 0x03 },
/* 090 */ { 0x03, 0x03 },
/* 091 */ { 0x03, 0x03 },
/* 092 */ { 0x03, 0x03 },
/* 093 */ { 0x03, 0x03 },
/* 094 */ { 0x03, 0x03 },
/* 095 */ { 0x03, 0x03 },
/* 096 */ { 0x03, 0x03 },
/* 097 */ { 0x03, 0x03 },
/* 098 */ { 0x03, 0x03 },
/* 099 */ { 0x03, 0x03 },
/* 09a */ { 0x03, 0x03 },
/* 09b */ { 0x03, 0x03 },
/* 09c */ { 0x03, 0x03 },
/* 09d */ { 0x03, 0x03 },
/* 09e */ { 0x03, 0x03 },
/* 09f */ { 0x03, 0x03 },
/* 0a0 */ { 0x03, 0x03 },
/* 0a1 */ { 0x03, 0x03 },
/* 0a2 */ { 0x03, 0x03 },
/* 0a3 */ { 0x03, 0x03 },
/* 0a4 */ { 0x03, 0x03 },
/* 0a5 */ { 0x03, 0x03 },
/* 0a6 */ { 0x03, 0x03 },
/* 0a7 */ { 0x03, 0x03 },
/* 0a8 */ { 0x03, 0x03 },
/* 0a9 */ { 0x03, 0x03 },
/* 0aa */ { 0x03, 0x03 },
/* 0ab */ { 0x03, 0x03 },
/* 0ac */ { 0x03, 0x03 },
/* 0ad */ { 0x03, 0x03 },
/* 0ae */ { 0x03, 0x03 },
/* 0af */ { 0x03, 0x03 },
/* 0b0 */ { 0x03, 0x03 },
/* 0b1 */ { 0x03, 0x03 },
/* 0b2 */ { 0x03, 0x03 },
/* 0b3 */ { 0x03, 0x03 },
/* 0b4 */ { 0x03, 0x03 },
/* 0b5 */ { 0x03, 0x03 },
/* 0b6 */ { 0x03, 0x03 },
/* 0b7 */ { 0x03, 0x03 },
/* 0b8 */ { 0x03, 0x03 },
/* 0b9 */ { 0x03, 0x03 },
/* 0ba */ { 0x03, 0x03 },
/* 0bb */ { 0x03, 0x03 },
/* 0bc */ { 0x03, 0x03 },
/* 0bd */ { 0x03, 0x03 },
/* 0be */ { 0x03, 0x03 },
/* 0bf */ { 0x03, 0x03 },
/* 0c0 */ { 0x04, 0x03 },
/* 0c1 */ { 0x04, 0x03 },
/* 0c2 */ { 0x04, 0x03 },
/* 0c3 */ { 0x04, 0x03 },
/* 0c4 */ { 0x04, 0x03 },
/* 0c5 */ { 0x04, 0x03 },
/* 0c6 */ { 0x04, 0x03 },
/* 0c7 */ { 0x04, 0x03 },
/* 0c8 */ { 0x04, 0x03 },
/* 0c9 */ { 0x04, 0x03 },
/* 0ca */ { 0x04, 0x03 },
/* 0cb */ { 0x04, 0x03 },
/* 0cc */ { 0x04, 0x03 },
/* 0cd */ { 0x04, 0x03 },
/* 0ce */ { 0x04, 0x03 },
/* 0cf */ { 0x04, 0x03 },
/* 0d0 */ { 0x04, 0x03 },
/* 0d1 */ { 0x04, 0x03 },
/* 0d2 */ { 0x04, 0x03 },
/* 0d3 */ { 0x04, 0x03 },
/* 0d4 */ { 0x04, 0x03 },
/* 0d5 */ { 0x04, 0x03 },
/* 0d6 */ { 0x04, 0x03 },
/* 0d7 */ { 0x04, 0x03 },
/* 0d8 */ { 0x04, 0x03 },
/* 0d9 */ { 0x04, 0x03 },
/* 0da */ { 0x04, 0x03 },
/* 0db */ { 0x04, 0x03 },
/* 0dc */ { 0x04, 0x03 },
/* 0dd */ { 0x04, 0x03 },
/* 0de */ { 0x04, 0x03 },
/* 0df */ { 0x04, 0x03 },
/* 0e0 */ { 0x04, 0x03 },
/* 0e1 */ { 0x04, 0x03 },
/* 0e2 */ { 0x04, 0x03 },
/* 0e3 */ { 0x04, 0x03 },
/* 0e4 */ { 0x04, 0x03 },
/* 0e5 */ { 0x04, 0x03 },
/* 0e6 */ { 0x04, 0x03 },
/* 0e7 */ { 0x04, 0x03 },
/* 0e8 */ { 0x04, 0x03 },
/* 0e9 */ { 0x04, 0x03 },
/* 0ea */ { 0x04, 0x03 },
/* 0eb */ { 0x04, 0x03 },
/* 0ec */ { 0x04, 0x03 },
/* 0ed */ { 0x04, 0x03 },
/* 0ee */ { 0x04, 0x03 },
/* 0ef */ { 0x04, 0x03 },
/* 0f0 */ { 0x04, 0x03 },
/* 0f1 */ { 0x04, 0x03 },
/* 0f2 */ { 0x04, 0x03 },
/* 0f3 */ { 0x04, 0x03 },
/* 0f4 */ { 0x04, 0x03 },
/* 0f5 */ { 0x04, 0x03 },
/* 0f6 */ { 0x04, 0x03 },
/* 0f7 */ { 0x04, 0x03 },
/* 0f8 */ { 0x04, 0x03 },
/* 0f9 */ { 0x04, 0x03 },
/* 0fa */ { 0x04, 0x03 },
/* 0fb */ { 0x04, 0x03 },
/* 0fc */ { 0x04, 0x03 },
/* 0fd */ { 0x04, 0x03 },
/* 0fe */ { 0x04, 0x03 },
/* 0ff */ { 0x04, 0x03 },
/* 100 */ { 0x05, 0x03 },
/* 101 */ { 0x05, 0x03 },
/* 102 */ { 0x05, 0x03 },
/* 103 */ { 0x05, 0x03 },
/* 104 */ { 0x05, 0x03 },
/* 105 */ { 0x05, 0x03 },
/* 106 */ { 0x05, 0x03 },
/* 107 */ { 0x05, 0x03 },
/* 108 */ { 0x05, 0x03 },
/* 109 */ { 0x05, 0x03 },
/* 10a */ { 0x05, 0x03 },
/* 10b */ { 0x05, 0x03 },
/* 10c */ { 0x05, 0x03 },
/* 10d */ { 0x05, 0x03 },
/* 10e */ { 0x05, 0x03 },
/* 10f */ { 0x05, 0x03 },
/* 110 */ { 0x05, 0x03 },
/* 111 */ { 0x05, 0x03 },
/* 112 */ { 0x05, 0x03 },
/* 113 */ { 0x05, 0x03 },
/* 114 */ { 0x05, 0x03 },
/* 115 */ { 0x05, 0x03 },
/* 116 */ { 0x05, 0x03 },
/* 117 */ { 0x05, 0x03 },
/* 118 */ { 0x05, 0x03 },
/* 119 */ { 0x05, 0x03 },
/* 11a */ { 0x05, 0x03 },
/* 11b */ { 0x05, 0x03 },
/* 11c */ { 0x05, 0x03 },
/* 11d */ { 0x05, 0x03 },
/* 11e */ { 0x05, 0x03 },
/* 11f */ { 0x05, 0x03 },
/* 120 */ { 0x05, 0x03 },
/* 121 */ { 0x05, 0x03 },
/* 122 */ { 0x05, 0x03 },
/* 123 */ { 0x05, 0x03 },
/* 124 */ { 0x05, 0x03 },
/* 125 */ { 0x05, 0x03 },
/* 126 */ { 0x05, 0x03 },
/* 127 */ { 0x05, 0x03 },
/* 128 */ { 0x05, 0x03 },
/* 129 */ { 0x05, 0x03 },
/* 12a */ { 0x05, 0x03 },
/* 12b */ { 0x05, 0x03 },
/* 12c */ { 0x05, 0x03 },
/* 12d */ { 0x05, 0x03 },
/* 12e */ { 0x05, 0x03 },
/* 12f */ { 0x05, 0x03 },
/* 130 */ { 0x05, 0x03 },
/* 131 */ { 0x05, 0x03 },
/* 132 */ { 0x05, 0x03 },
/* 133 */ { 0x05, 0x03 },
/* 134 */ { 0x05, 0x03 },
/* 135 */ { 0x05, 0x03 },
/* 136 */ { 0x05, 0x03 },
/* 137 */ { 0x05, 0x03 },
/* 138 */ { 0x05, 0x03 },
/* 139 */ { 0x05, 0x03 },
/* 13a */ { 0x05, 0x03 },
/* 13b */ { 0x05, 0x03 },
/* 13c */ { 0x05, 0x03 },
/* 13d */ { 0x05, 0x03 },
/* 13e */ { 0x05, 0x03 },
/* 13f */ { 0x05, 0x03 },
/* 140 */ { 0x06, 0x03 },
/* 141 */ { 0x06, 0x03 },
/* 142 */ { 0x06, 0x03 },
/* 143 */ { 0x06, 0x03 },
/* 144 */ { 0x06, 0x03 },
/* 145 */ { 0x06, 0x03 },
/* 146 */ { 0x06, 0x03 },
/* 147 */ { 0x06, 0x03 },
/* 148 */ { 0x06, 0x03 },
/* 149 */ { 0x06, 0x03 },
/* 14a */ { 0x06, 0x03 },
/* 14b */ { 0x06, 0x03 },
/* 14c */ { 0x06, 0x03 },
/* 14d */ { 0x06, 0x03 },
/* 14e */ { 0x06, 0x03 },
/* 14f */ { 0x06, 0x03 },
/* 150 */ { 0x06, 0x03 },
/* 151 */ { 0x06, 0x03 },
/* 152 */ { 0x06, 0x03 },
/* 153 */ { 0x06, 0x03 },
/* 154 */ { 0x06, 0x03 },
/* 155 */ { 0x06, 0x03 },
/* 156 */ { 0x06, 0x03 },
/* 157 */ { 0x06, 0x03 },
/* 158 */ { 0x06, 0x03 },
/* 159 */ { 0x06, 0x03 },
/* 15a */ { 0x06, 0x03 },
/* 15b */ { 0x06, 0x03 },
/* 15c */ { 0x06, 0x03 },
/* 15d */ { 0x06, 0x03 },
/* 15e */ { 0x06, 0x03 },
/* 15f */ { 0x06, 0x03 },
/* 160 */ { 0x06, 0x03 },
/* 161 */ { 0x06, 0x03 },
/* 162 */ { 0x06, 0x03 },
/* 163 */ { 0x06, 0x03 },
/* 164 */ { 0x06, 0x03 },
/* 165 */ { 0x06, 0x03 },
/* 166 */ { 0x06, 0x03 },
/* 167 */ { 0x06, 0x03 },
/* 168 */ { 0x06, 0x03 },
/* 169 */ { 0x06, 0x03 },
/* 16a */ { 0x06, 0x03 },
/* 16b */ { 0x06, 0x03 },
/* 16c */ { 0x06, 0x03 },
/* 16d */ { 0x06, 0x03 },
/* 16e */ { 0x06, 0x03 },
/* 16f */ { 0x06, 0x03 },
/* 170 */ { 0x06, 0x03 },
/* 171 */ { 0x06, 0x03 },
/* 172 */ { 0x06, 0x03 },
/* 173 */ { 0x06, 0x03 },
/* 174 */ { 0x06, 0x03 },
/* 175 */ { 0x06, 0x03 },
/* 176 */ { 0x06, 0x03 },
/* 177 */ { 0x06, 0x03 },
/* 178 */ { 0x06, 0x03 },
/* 179 */ { 0x06, 0x03 },
/* 17a */ { 0x06, 0x03 },
/* 17b */ { 0x06, 0x03 },
/* 17c */ { 0x06, 0x03 },
/* 17d */ { 0x06, 0x03 },
/* 17e */ { 0x06, 0x03 },
/* 17f */ { 0x06, 0x03 },
/* 180 */ { 0x07, 0x03 },
/* 181 */ { 0x07, 0x03 },
/* 182 */ { 0x07, 0x03 },
/* 183 */ { 0x07, 0x03 },
/* 184 */ { 0x07, 0x03 },
/* 185 */ { 0x07, 0x03 },
/* 186 */ { 0x07, 0x03 },
/* 187 */ { 0x07, 0x03 },
/* 188 */ { 0x07, 0x03 },
/* 189 */ { 0x07, 0x03 },
/* 18a */ { 0x07, 0x03 },
/* 18b */ { 0x07, 0x03 },
/* 18c */ { 0x07, 0x03 },
/* 18d */ { 0x07, 0x03 },
/* 18e */ { 0x07, 0x03 },
/* 18f */ { 0x07, 0x03 },
/* 190 */ { 0x07, 0x03 },
/* 191 */ { 0x07, 0x03 },
/* 192 */ { 0x07, 0x03 },
/* 193 */ { 0x07, 0x03 },
/* 194 */ { 0x07, 0x03 },
/* 195 */ { 0x07, 0x03 },
/* 196 */ { 0x07, 0x03 },
/* 197 */ { 0x07, 0x03 },
/* 198 */ { 0x07, 0x03 },
/* 199 */ { 0x07, 0x03 },
/* 19a */ { 0x07, 0x03 },
/* 19b */ { 0x07, 0x03 },
/* 19c */ { 0x07, 0x03 },
/* 19d */ { 0x07, 0x03 },
/* 19e */ { 0x07, 0x03 },
/* 19f */ { 0x07, 0x03 },
/* 1a0 */ { 0x07, 0x03 },
/* 1a1 */ { 0x07, 0x03 },
/* 1a2 */ { 0x07, 0x03 },
/* 1a3 */ { 0x07, 0x03 },
/* 1a4 */ { 0x07, 0x03 },
/* 1a5 */ { 0x07, 0x03 },
/* 1a6 */ { 0x07, 0x03 },
/* 1a7 */ { 0x07, 0x03 },
/* 1a8 */ { 0x07, 0x03 },
/* 1a9 */ { 0x07, 0x03 },
/* 1aa */ { 0x07, 0x03 },
/* 1ab */ { 0x07, 0x03 },
/* 1ac */ { 0x07, 0x03 },
/* 1ad */ { 0x07, 0x03 },
/* 1ae */ { 0x07, 0x03 },
/* 1af */ { 0x07, 0x03 },
/* 1b0 */ { 0x07, 0x03 },
/* 1b1 */ { 0x07, 0x03 },
/* 1b2 */ { 0x07, 0x03 },
/* 1b3 */ { 0x07, 0x03 },
/* 1b4 */ { 0x07, 0x03 },
/* 1b5 */ { 0x07, 0x03 },
/* 1b6 */ { 0x07, 0x03 },
/* 1b7 */ { 0x07, 0x03 },
/* 1b8 */ { 0x07, 0x03 },
/* 1b9 */ { 0x07, 0x03 },
/* 1ba */ { 0x07, 0x03 },
/* 1bb */ { 0x07, 0x03 },
/* 1bc */ { 0x07, 0x03 },
/* 1bd */ { 0x07, 0x03 },
/* 1be */ { 0x07, 0x03 },
/* 1bf */ { 0x07, 0x03 },
/* 1c0 */ { 0x01, 0x04 },
/* 1c1 */ { 0x01, 0x04 },
/* 1c2 */ { 0x01, 0x04 },
/* 1c3 */ { 0x01, 0x04 },
/* 1c4 */ { 0x01, 0x04 },
/* 1c5 */ { 0x01, 0x04 },
/* 1c6 */ { 0x01, 0x04 },
/* 1c7 */ { 0x01, 0x04 },
/* 1c8 */ { 0x01, 0x04 },
/* 1c9 */ { 0x01, 0x04 },
/* 1ca */ { 0x01, 0x04 },
/* 1cb */ { 0x01, 0x04 },
/* 1cc */ { 0x01, 0x04 },
/* 1cd */ { 0x01, 0x04 },
/* 1ce */ { 0x01, 0x04 },
/* 1cf */ { 0x01, 0x04 },
/* 1d0 */ { 0x01, 0x04 },
/* 1d1 */ { 0x01, 0x04 },
/* 1d2 */ { 0x01, 0x04 },
/* 1d3 */ { 0x01, 0x04 },
/* 1d4 */ { 0x01, 0x04 },
/* 1d5 */ { 0x01, 0x04 },
/* 1d6 */ { 0x01, 0x04 },
/* 1d7 */ { 0x01, 0x04 },
/* 1d8 */ { 0x01, 0x04 },
/* 1d9 */ { 0x01, 0x04 },
/* 1da */ { 0x01, 0x04 },
/* 1db */ { 0x01, 0x04 },
/* 1dc */ { 0x01, 0x04 },
/* 1dd */ { 0x01, 0x04 },
/* 1de */ { 0x01, 0x04 },
/* 1df */ { 0x01, 0x04 },
/* 1e0 */ { 0x08, 0x06 },
/* 1e1 */ { 0x08, 0x06 },
/* 1e2 */ { 0x08, 0x06 },
/* 1e3 */ { 0x08, 0x06 },
/* 1e4 */ { 0x08, 0x06 },
/* 1e5 */ { 0x08, 0x06 },
/* 1e6 */ { 0x08, 0x06 },
/* 1e7 */ { 0x08, 0x06 },
/* 1e8 */ { 0x09, 0x07 },
/* 1e9 */ { 0x09, 0x07 },
/* 1ea */ { 0x09, 0x07 },
/* 1eb */ { 0x09, 0x07 },
/* 1ec */ { 0x0f, 0x07 },
/* 1ed */ { 0x0f, 0x07 },
/* 1ee */ { 0x0f, 0x07 },
/* 1ef */ { 0x0f, 0x07 },
/* 1f0 */ { 0x10, 0x09 },
/* 1f1 */ { 0x11, 0x09 },
/* 1f2 */ { 0x12, 0x09 },
/* 1f3 */ { 0x13, 0x09 },
/* 1f4 */ { 0x14, 0x09 },
/* 1f5 */ { 0x15, 0x09 },
/* 1f6 */ { 0x16, 0x09 },
/* 1f7 */ { 0x17, 0x09 },
/* 1f8 */ { 0x18, 0x09 },
/* 1f9 */ { 0x19, 0x09 },
/* 1fa */ { 0x1a, 0x09 },
/* 1fb */ { 0x1b, 0x09 },
/* 1fc */ { 0x1c, 0x09 },
/* 1fd */ { 0x1d, 0x09 },
/* 1fe */ { 0x1e, 0x09 },
/* 1ff */ { 0x1f, 0x09 },

View File

@ -1,457 +0,0 @@
// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
#include "Blip_Buffer.h"
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module 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 Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#ifdef BLARGG_ENABLE_OPTIMIZER
#include BLARGG_ENABLE_OPTIMIZER
#endif
int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
Blip_Buffer::Blip_Buffer()
{
factor_ = (blip_u64)ULLONG_MAX;
offset_ = 0;
buffer_ = 0;
buffer_size_ = 0;
sample_rate_ = 0;
reader_accum_ = 0;
bass_shift_ = 0;
clock_rate_ = 0;
bass_freq_ = 16;
length_ = 0;
// assumptions code makes about implementation-defined features
#ifndef NDEBUG
// right shift of negative value preserves sign
buf_t_ i = -0x7FFFFFFE;
assert( (i >> 1) == -0x3FFFFFFF );
// casting to short truncates to 16 bits and sign-extends
i = 0x18000;
assert( (short) i == -0x8000 );
#endif
}
Blip_Buffer::~Blip_Buffer()
{
if ( buffer_size_ != silent_buf_size )
free( buffer_ );
}
Silent_Blip_Buffer::Silent_Blip_Buffer()
{
factor_ = 0;
buffer_ = buf;
buffer_size_ = silent_buf_size;
memset( buf, 0, sizeof buf ); // in case machine takes exception for signed overflow
}
void Blip_Buffer::clear( int entire_buffer )
{
offset_ = 0;
reader_accum_ = 0;
modified_ = 0;
if ( buffer_ )
{
long count = (entire_buffer ? buffer_size_ : samples_avail());
memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) );
}
}
Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
{
if ( buffer_size_ == silent_buf_size )
{
assert( 0 );
return "Internal (tried to resize Silent_Blip_Buffer)";
}
// start with maximum length that resampled time can represent
blip_s64 new_size = (ULLONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64;
// simple safety check, since code elsewhere may not be safe for sizes approaching (2 ^ 31).
if(new_size > ((1LL << 30) - 1))
new_size = (1LL << 30) - 1;
if ( msec != blip_max_length )
{
blip_s64 s = ((blip_s64)new_rate * (msec + 1) + 999) / 1000;
if ( s < new_size )
new_size = s;
else
assert( 0 ); // fails if requested buffer length exceeds limit
}
if ( buffer_size_ != new_size )
{
void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ );
if ( !p )
return "Out of memory";
//if(new_size > buffer_size_)
// memset(buffer_ + buffer_size_, 0, (new_size + blip_buffer_extra_) * sizeof *buffer_
buffer_ = (buf_t_*) p;
}
buffer_size_ = new_size;
assert( buffer_size_ != silent_buf_size );
// update things based on the sample rate
sample_rate_ = new_rate;
length_ = new_size * 1000 / new_rate - 1;
if ( msec )
assert( length_ == msec ); // ensure length is same as that passed in
if ( clock_rate_ )
clock_rate( clock_rate_ );
bass_freq( bass_freq_ );
clear();
return 0; // success
}
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const
{
double ratio = (double) sample_rate_ / rate;
blip_s64 factor = (blip_s64) floor( ratio * (1LL << BLIP_BUFFER_ACCURACY) + 0.5 );
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
return (blip_resampled_time_t) factor;
}
void Blip_Buffer::bass_freq( int freq )
{
bass_freq_ = freq;
int shift = 31;
if ( freq > 0 )
{
shift = 13;
long f = (freq << 16) / sample_rate_;
while ( (f >>= 1) && --shift ) { }
}
bass_shift_ = shift;
//printf("%d\n", bass_shift_);
}
void Blip_Buffer::end_frame( blip_time_t t )
{
offset_ += t * factor_;
assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length
}
void Blip_Buffer::remove_silence( long count )
{
assert( count <= samples_avail() ); // tried to remove more samples than available
offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
}
long Blip_Buffer::count_samples( blip_time_t t ) const
{
unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
return (long) (last_sample - first_sample);
}
blip_time_t Blip_Buffer::count_clocks( long count ) const
{
if ( !factor_ )
{
assert( 0 ); // sample rate and clock rates must be set first
return 0;
}
if ( count > buffer_size_ )
count = buffer_size_;
blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
}
void Blip_Buffer::remove_samples( long count )
{
if ( count )
{
remove_silence( count );
// copy remaining samples to beginning and clear old samples
long remain = samples_avail() + blip_buffer_extra_;
memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
memset( buffer_ + remain, 0, count * sizeof *buffer_ );
}
}
// Blip_Synth_
Blip_Synth_Fast_::Blip_Synth_Fast_()
{
buf = 0;
last_amp = 0;
delta_factor = 0;
}
void Blip_Synth_Fast_::volume_unit( double new_unit )
{
delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5);
}
#if !BLIP_BUFFER_FAST
Blip_Synth_::Blip_Synth_( short* p, int w ) :
impulses( p ),
width( w )
{
volume_unit_ = 0.0;
kernel_unit = 0;
buf = 0;
last_amp = 0;
delta_factor = 0;
}
#undef PI
#define PI 3.1415926535897932384626433832795029
static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
{
if ( cutoff >= 0.999 )
cutoff = 0.999;
if ( treble < -300.0 )
treble = -300.0;
if ( treble > 5.0 )
treble = 5.0;
double const maxh = 4096.0;
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
double const to_angle = PI / 2 / maxh / oversample;
for ( int i = 0; i < count; i++ )
{
double angle = ((i - count) * 2 + 1) * to_angle;
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
double cos_nc_angle = cos( maxh * cutoff * angle );
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
double cos_angle = cos( angle );
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
double b = 2.0 - cos_angle - cos_angle;
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
}
}
void blip_eq_t::generate( float* out, int count ) const
{
// lower cutoff freq for narrow kernels with their wider transition band
// (8 points->1.49, 16 points->1.15)
double oversample = blip_res * 2.25 / count + 0.85;
double half_rate = sample_rate * 0.5;
if ( cutoff_freq )
oversample = half_rate / cutoff_freq;
double cutoff = rolloff_freq * oversample / half_rate;
gen_sinc( out, count, blip_res * oversample, treble, cutoff );
// apply (half of) hamming window
double to_fraction = PI / (count - 1);
for ( int i = count; i--; )
out [i] *= 0.54f - 0.46f * (float) cos( i * to_fraction );
}
void Blip_Synth_::adjust_impulse()
{
// sum pairs for each phase and add error correction to end of first half
int const size = impulses_size();
for ( int p = blip_res; p-- >= blip_res / 2; )
{
int p2 = blip_res - 2 - p;
long error = kernel_unit;
for ( int i = 1; i < size; i += blip_res )
{
error -= impulses [i + p ];
error -= impulses [i + p2];
}
if ( p == p2 )
error /= 2; // phase = 0.5 impulse uses same half for both sides
impulses [size - blip_res + p] += (short) error;
//printf( "error: %ld\n", error );
}
//for ( int i = blip_res; i--; printf( "\n" ) )
// for ( int j = 0; j < width / 2; j++ )
// printf( "%5ld,", impulses [j * blip_res + i + 1] );
}
void Blip_Synth_::treble_eq( blip_eq_t const& eq )
{
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
int const half_size = blip_res / 2 * (width - 1);
eq.generate( &fimpulse [blip_res], half_size );
int i;
// need mirror slightly past center for calculation
for ( i = blip_res; i--; )
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
// starts at 0
for ( i = 0; i < blip_res; i++ )
fimpulse [i] = 0.0f;
// find rescale factor
double total = 0.0;
for ( i = 0; i < half_size; i++ )
total += fimpulse [blip_res + i];
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
//double const base_unit = 37888.0; // allows treble to +5 dB
double const base_unit = 32768.0; // necessary for blip_unscaled to work
double rescale = base_unit / 2 / total;
kernel_unit = (long) base_unit;
// integrate, first difference, rescale, convert to int
double sum = 0.0;
double next = 0.0;
int const impulses_size_local = this->impulses_size();
for ( i = 0; i < impulses_size_local; i++ )
{
impulses [i] = (short) floor( (next - sum) * rescale + 0.5 );
sum += fimpulse [i];
next += fimpulse [i + blip_res];
}
adjust_impulse();
// volume might require rescaling
double vol = volume_unit_;
if ( vol )
{
volume_unit_ = 0.0;
volume_unit( vol );
}
}
void Blip_Synth_::volume_unit( double new_unit )
{
if ( new_unit != volume_unit_ )
{
// use default eq if it hasn't been set yet
if ( !kernel_unit )
treble_eq( -8.0 );
volume_unit_ = new_unit;
double factor = new_unit * (1L << blip_sample_bits) / kernel_unit;
if ( factor > 0.0 )
{
int shift = 0;
// if unit is really small, might need to attenuate kernel
while ( factor < 2.0 )
{
shift++;
factor *= 2.0;
}
if ( shift )
{
kernel_unit >>= shift;
assert( kernel_unit > 0 ); // fails if volume unit is too low
// keep values positive to avoid round-towards-zero of sign-preserving
// right shift for negative values
long offset = 0x8000 + (1 << (shift - 1));
long offset2 = 0x8000 >> shift;
for ( int i = impulses_size(); i--; )
impulses [i] = (short) (((impulses [i] + offset) >> shift) - offset2);
adjust_impulse();
}
}
delta_factor = (int) floor( factor + 0.5 );
//printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit );
}
}
#endif
long Blip_Buffer::read_samples( blip_sample_t* BLIP_RESTRICT out, long max_samples, int stereo )
{
long count = samples_avail();
if ( count > max_samples )
count = max_samples;
if ( count )
{
int const bass = BLIP_READER_BASS( *this );
BLIP_READER_BEGIN( reader, *this );
if ( !stereo )
{
for ( blip_long n = count; n; --n )
{
blip_long s = BLIP_READER_READ( reader );
if ( (blip_sample_t) s != s )
s = 0x7FFF - (s >> 24);
*out++ = (blip_sample_t) s;
BLIP_READER_NEXT( reader, bass );
}
}
else
{
for ( blip_long n = count; n; --n )
{
blip_long s = BLIP_READER_READ( reader );
if ( (blip_sample_t) s != s )
s = 0x7FFF - (s >> 24);
*out = (blip_sample_t) s;
out += 2;
BLIP_READER_NEXT( reader, bass );
}
}
BLIP_READER_END( reader, *this );
remove_samples( count );
}
return count;
}
void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
{
if ( buffer_size_ == silent_buf_size )
{
assert( 0 );
return;
}
buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
int const sample_shift = blip_sample_bits - 16;
int prev = 0;
while ( count-- )
{
blip_long s = (blip_long) *in++ << sample_shift;
*out += s - prev;
prev = s;
++out;
}
*out -= prev;
}

View File

@ -1,498 +0,0 @@
// Band-limited sound synthesis buffer
// Various changes and hacks for use in Mednafen.
#ifdef __GNUC__
#define blip_inline inline __attribute__((always_inline))
#else
#define blip_inline inline
#endif
#include <limits.h>
#include <inttypes.h>
// Blip_Buffer 0.4.1
#ifndef BLIP_BUFFER_H
#define BLIP_BUFFER_H
// Internal
typedef int32_t blip_long;
typedef uint32_t blip_ulong;
typedef int64_t blip_s64;
typedef uint64_t blip_u64;
// Time unit at source clock rate
typedef blip_long blip_time_t;
// Output samples are 16-bit signed, with a range of -32768 to 32767
typedef short blip_sample_t;
enum { blip_sample_max = 32767 };
class Blip_Buffer {
public:
typedef const char* blargg_err_t;
// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
// isn't enough memory, returns error without affecting current buffer setup.
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
// Set number of source time units per second
void clock_rate( long );
// End current time frame of specified duration and make its samples available
// (along with any still-unread samples) for reading with read_samples(). Begins
// a new time frame at the end of the current frame.
void end_frame( blip_time_t time );
// Read at most 'max_samples' out of buffer into 'dest', removing them from from
// the buffer. Returns number of samples actually read and removed. If stereo is
// true, increments 'dest' one extra time after writing each sample, to allow
// easy interleving of two channels into a stereo output buffer.
long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
// Additional optional features
// Current output sample rate
long sample_rate() const;
// Length of buffer, in milliseconds
int length() const;
// Number of source time units per second
long clock_rate() const;
// Set frequency high-pass filter frequency, where higher values reduce bass more
void bass_freq( int frequency );
// Number of samples delay from synthesis to samples read out
int output_latency() const;
// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
// false, just clears out any samples waiting rather than the entire buffer.
void clear( int entire_buffer = 1 );
// Number of samples available for reading with read_samples()
long samples_avail() const;
// Remove 'count' samples from those waiting to be read
void remove_samples( long count );
// Experimental features
// Count number of clocks needed until 'count' samples will be available.
// If buffer can't even hold 'count' samples, returns number of clocks until
// buffer becomes full.
blip_time_t count_clocks( long count ) const;
// Number of raw samples that can be mixed within frame of specified duration.
long count_samples( blip_time_t duration ) const;
// Mix 'count' samples from 'buf' into buffer.
void mix_samples( blip_sample_t const* buf, long count );
// not documented yet
void set_modified() { modified_ = 1; }
int clear_modified() { int b = modified_; modified_ = 0; return b; }
typedef blip_u64 blip_resampled_time_t;
void remove_silence( long count );
blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
public:
Blip_Buffer();
~Blip_Buffer();
// Deprecated
typedef blip_resampled_time_t resampled_time_t;
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
private:
// noncopyable
Blip_Buffer( const Blip_Buffer& );
Blip_Buffer& operator = ( const Blip_Buffer& );
public:
typedef blip_time_t buf_t_;
blip_u64 factor_;
blip_resampled_time_t offset_;
buf_t_* buffer_;
blip_long buffer_size_;
blip_long reader_accum_;
int bass_shift_;
private:
long sample_rate_;
long clock_rate_;
int bass_freq_;
int length_;
int modified_;
friend class Blip_Reader;
};
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define BLIP_BUFFER_ACCURACY 32
#define BLIP_PHASE_BITS 8
// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
// but reduce maximum buffer size.
//#ifndef BLIP_BUFFER_ACCURACY
// #define BLIP_BUFFER_ACCURACY 16
//#endif
// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
// noticeable broadband noise when synthesizing high frequency square waves.
// Affects size of Blip_Synth objects since they store the waveform directly.
//#ifndef BLIP_PHASE_BITS
// #if BLIP_BUFFER_FAST
// #define BLIP_PHASE_BITS 8
// #else
// #define BLIP_PHASE_BITS 6
// #endif
//#endif
// Internal
typedef blip_u64 blip_resampled_time_t;
int const blip_widest_impulse_ = 16;
int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
int const blip_res = 1 << BLIP_PHASE_BITS;
class blip_eq_t;
class Blip_Synth_Fast_ {
public:
Blip_Buffer* buf;
int last_amp;
int delta_factor;
void volume_unit( double );
Blip_Synth_Fast_();
void treble_eq( blip_eq_t const& ) { }
};
class Blip_Synth_ {
public:
Blip_Buffer* buf;
int last_amp;
int delta_factor;
void volume_unit( double );
Blip_Synth_( short* impulses, int width );
void treble_eq( blip_eq_t const& );
private:
double volume_unit_;
short* const impulses;
int const width;
blip_long kernel_unit;
int impulses_size() const { return blip_res / 2 * width + 1; }
void adjust_impulse();
};
// Quality level. Start with blip_good_quality.
const int blip_med_quality = 8;
const int blip_good_quality = 12;
const int blip_high_quality = 16;
// Range specifies the greatest expected change in amplitude. Calculate it
// by finding the difference between the maximum and minimum expected
// amplitudes (max - min).
template<int quality,int range>
class Blip_Synth {
public:
// Set overall volume of waveform
void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
// Configure low-pass filter (see blip_buffer.txt)
void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
// Get/set Blip_Buffer used for output
Blip_Buffer* output() const { return impl.buf; }
void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
// Update amplitude of waveform at given time. Using this requires a separate
// Blip_Synth for each waveform.
void update( blip_time_t time, int amplitude );
// Low-level interface
// Add an amplitude transition of specified delta, optionally into specified buffer
// rather than the one set with output(). Delta can be positive or negative.
// The actual change in amplitude is delta * (volume / range)
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
// Works directly in terms of fractional output samples. Contact author for more info.
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
// Same as offset(), except code is inlined for higher performance
void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}
void offset_inline( blip_time_t t, int delta ) const {
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}
private:
#if BLIP_BUFFER_FAST
Blip_Synth_Fast_ impl;
#else
Blip_Synth_ impl;
typedef short imp_t;
imp_t impulses [blip_res * (quality / 2) + 1];
public:
Blip_Synth() : impl( impulses, quality ) { }
#endif
};
// Low-pass equalization parameters
class blip_eq_t {
public:
// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
// treble, small positive values (0 to 5.0) increase treble.
blip_eq_t( double treble_db = 0 );
// See blip_buffer.txt
blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
private:
double treble;
long rolloff_freq;
long sample_rate;
long cutoff_freq;
void generate( float* out, int count ) const;
friend class Blip_Synth_;
};
int const blip_sample_bits = 30;
// Dummy Blip_Buffer to direct sound output to, for easy muting without
// having to stop sound code.
class Silent_Blip_Buffer : public Blip_Buffer {
buf_t_ buf [blip_buffer_extra_ + 1];
public:
// The following cannot be used (an assertion will fail if attempted):
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
blip_time_t count_clocks( long count ) const;
void mix_samples( blip_sample_t const* buf, long count );
Silent_Blip_Buffer();
};
#if defined (__GNUC__) || _MSC_VER >= 1100
#define BLIP_RESTRICT __restrict
#else
#define BLIP_RESTRICT
#endif
// Optimized reading from Blip_Buffer, for use in custom sample output
// Begin reading from buffer. Name should be unique to the current block.
#define BLIP_READER_BEGIN( name, blip_buffer ) \
const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
blip_long name##_reader_accum = (blip_buffer).reader_accum_
// Get value to pass to BLIP_READER_NEXT()
#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
// code at the cost of having no bass control
int const blip_reader_default_bass = 9;
// Current sample
#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))
// Current raw sample in full internal resolution
#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)
// Advance to next sample
#define BLIP_READER_NEXT( name, bass ) \
(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
// End reading samples from buffer. The number of samples read must now be removed
// using Blip_Buffer::remove_samples().
#define BLIP_READER_END( name, blip_buffer ) \
(void) ((blip_buffer).reader_accum_ = name##_reader_accum)
// Compatibility with older version
const long blip_unscaled = 65535;
const int blip_low_quality = blip_med_quality;
const int blip_best_quality = blip_high_quality;
// Deprecated; use BLIP_READER macros as follows:
// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
// r.read() -> BLIP_READER_READ( r )
// r.read_raw() -> BLIP_READER_READ_RAW( r )
// r.next( bass ) -> BLIP_READER_NEXT( r, bass )
// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )
// r.end( buf ) -> BLIP_READER_END( r, buf )
class Blip_Reader {
public:
int begin( Blip_Buffer& );
blip_long read() const { return accum >> (blip_sample_bits - 16); }
blip_long read_raw() const { return accum; }
void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }
private:
const Blip_Buffer::buf_t_* buf;
blip_long accum;
};
// End of public interface
#include <assert.h>
template<int quality,int range>
blip_inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
int delta, Blip_Buffer* blip_buf ) const
{
// Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
// need for a longer buffer as set by set_sample_rate().
assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
delta *= impl.delta_factor;
blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
#if BLIP_BUFFER_FAST
blip_long left = buf [0] + delta;
// Kind of crappy, but doing shift after multiply results in overflow.
// Alternate way of delaying multiply by delta_factor results in worse
// sub-sample resolution.
blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
left -= right;
right += buf [1];
buf [0] = left;
buf [1] = right;
#else
int const fwd = (blip_widest_impulse_ - quality) / 2;
int const rev = fwd + quality - 2;
int const mid = quality / 2 - 1;
imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
// straight forward implementation resulted in better code on GCC for x86
#define ADD_IMP( out, in ) \
buf [out] += (blip_long) imp [blip_res * (in)] * delta
#define BLIP_FWD( i ) {\
ADD_IMP( fwd + i, i );\
ADD_IMP( fwd + 1 + i, i + 1 );\
}
#define BLIP_REV( r ) {\
ADD_IMP( rev - r, r + 1 );\
ADD_IMP( rev + 1 - r, r );\
}
BLIP_FWD( 0 )
if ( quality > 8 ) BLIP_FWD( 2 )
if ( quality > 12 ) BLIP_FWD( 4 )
{
ADD_IMP( fwd + mid - 1, mid - 1 );
ADD_IMP( fwd + mid , mid );
imp = impulses + phase;
}
if ( quality > 12 ) BLIP_REV( 6 )
if ( quality > 8 ) BLIP_REV( 4 )
BLIP_REV( 2 )
ADD_IMP( rev , 1 );
ADD_IMP( rev + 1, 0 );
#else
// for RISC processors, help compiler by reading ahead of writes
#define BLIP_FWD( i ) {\
blip_long t0 = i0 * delta + buf [fwd + i];\
blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\
i0 = imp [blip_res * (i + 2)];\
buf [fwd + i] = t0;\
buf [fwd + 1 + i] = t1;\
}
#define BLIP_REV( r ) {\
blip_long t0 = i0 * delta + buf [rev - r];\
blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\
i0 = imp [blip_res * (r - 1)];\
buf [rev - r] = t0;\
buf [rev + 1 - r] = t1;\
}
blip_long i0 = *imp;
BLIP_FWD( 0 )
if ( quality > 8 ) BLIP_FWD( 2 )
if ( quality > 12 ) BLIP_FWD( 4 )
{
blip_long t0 = i0 * delta + buf [fwd + mid - 1];
blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ];
imp = impulses + phase;
i0 = imp [blip_res * mid];
buf [fwd + mid - 1] = t0;
buf [fwd + mid ] = t1;
}
if ( quality > 12 ) BLIP_REV( 6 )
if ( quality > 8 ) BLIP_REV( 4 )
BLIP_REV( 2 )
blip_long t0 = i0 * delta + buf [rev ];
blip_long t1 = *imp * delta + buf [rev + 1];
buf [rev ] = t0;
buf [rev + 1] = t1;
#endif
#endif
}
#undef BLIP_FWD
#undef BLIP_REV
template<int quality,int range>
#if BLIP_BUFFER_FAST
blip_inline
#endif
void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
{
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}
template<int quality,int range>
#if BLIP_BUFFER_FAST
blip_inline
#endif
void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
{
int delta = amp - impl.last_amp;
impl.last_amp = amp;
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}
blip_inline blip_eq_t::blip_eq_t( double t ) :
treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
blip_inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
blip_inline int Blip_Buffer::length() const { return length_; }
blip_inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
blip_inline long Blip_Buffer::sample_rate() const { return sample_rate_; }
blip_inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
blip_inline long Blip_Buffer::clock_rate() const { return clock_rate_; }
blip_inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
blip_inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
{
buf = blip_buf.buffer_;
accum = blip_buf.reader_accum_;
return blip_buf.bass_shift_;
}
int const blip_max_length = 0;
int const blip_default_length = 250;
#endif

View File

@ -1,803 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* 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
*/
// Don't pass more than about 40ms worth of audio data to Resample()
// at a time.
#define _GNU_SOURCE
#include "../defs.h"
#include <math.h>
#include <assert.h>
#include <limits.h>
#include "OwlResampler.h"
//#include "../cputest/cputest.h"
#if defined(ARCH_POWERPC_ALTIVEC) && defined(HAVE_ALTIVEC_H)
#include <altivec.h>
#endif
#ifdef __ARM_NEON__
#include <arm_neon.h>
#endif
#ifdef __FAST_MATH__
#error "OwlResampler.cpp not compatible with unsafe math optimizations!"
#endif
OwlBuffer::OwlBuffer()
{
assert(sizeof(I32_F_Pudding) == 4);
assert(sizeof(float) == 4);
memset(HRBuf, 0, sizeof(HRBuf));
accum = 0;
filter_state[0] = 0;
filter_state[1] = 0;
leftover = 0;
InputIndex = 0;
InputPhase = 0;
debias = 0;
}
OwlBuffer::~OwlBuffer()
{
}
template<unsigned DoExMix, bool Integrate, unsigned IntegrateShift, bool Lowpass, bool Highpass, bool FloatOutput>
static int32 ProcessLoop(unsigned count, int32 a, int32* b, int32* exmix0 = NULL, int32* exmix1 = NULL, unsigned lp_shift = 0, unsigned hp_shift = 0, int64* f_in = NULL)
{
int64 lp_f;
int64 hp_f;
if(Lowpass)
{
lp_f = f_in[0];
}
if(Highpass)
{
hp_f = f_in[1];
}
while(count--)
{
int32 tmp;
if(Integrate)
{
a += *b;
tmp = a >> IntegrateShift;
}
else
tmp = *b;
if(Lowpass)
{
lp_f += ((int64)((uint64)(int64)tmp << 16) - lp_f) >> lp_shift;
tmp = lp_f >> 16;
}
if(Highpass)
{
hp_f += ((int64)((uint64)(int64)tmp << 16) - hp_f) >> hp_shift;
tmp = tmp - (hp_f >> 16);
}
if(DoExMix >= 1)
{
tmp += *exmix0;
exmix0++;
}
if(DoExMix >= 2)
{
tmp += *exmix1;
exmix1++;
}
if(FloatOutput)
*(float*)b = tmp;
else
*b = tmp;
b++;
}
if(Lowpass)
f_in[0] = lp_f;
if(Highpass)
f_in[1] = hp_f;
return(a);
}
void OwlBuffer::ResampleSkipped(unsigned count)
{
memmove(HRBuf, &HRBuf[count], HRBUF_OVERFLOW_PADDING * sizeof(HRBuf[0]));
memset(&HRBuf[HRBUF_OVERFLOW_PADDING], 0, count * sizeof(HRBuf[0]));
}
void OwlBuffer::Integrate(unsigned count, unsigned lp_shift, unsigned hp_shift, RavenBuffer* mixin0, RavenBuffer* mixin1)
{
//lp_shift = hp_shift = 0;
if(lp_shift != 0 || hp_shift != 0)
{
if(mixin0 && mixin1)
accum = ProcessLoop<2, true, 3, true, true, true>(count, accum, Buf(), mixin0->Buf(), mixin1->Buf(), lp_shift, hp_shift, filter_state);
else if(mixin0)
accum = ProcessLoop<1, true, 3, true, true, true>(count, accum, Buf(), mixin0->Buf(), NULL, lp_shift, hp_shift, filter_state);
else
accum = ProcessLoop<0, true, 3, true, true, true>(count, accum, Buf(), NULL, NULL, lp_shift, hp_shift, filter_state);
}
else
{
if(mixin0 && mixin1)
accum = ProcessLoop<2, true, 3, false, false, true>(count, accum, Buf(), mixin0->Buf(), mixin1->Buf());
else if(mixin0)
accum = ProcessLoop<1, true, 3, false, false, true>(count, accum, Buf(), mixin0->Buf());
else
accum = ProcessLoop<0, true, 3, false, false, true>(count, accum, Buf());
}
if(accum >= 32767 * 256 * 8 || accum <= -32767 * 256 * 8)
{
//printf("Possible delta sample loss; accum=%d\n", accum);
}
}
//
//
//
RavenBuffer::RavenBuffer()
{
memset(BB, 0, sizeof(BB));
accum = 0;
filter_state[0] = 0;
filter_state[1] = 0;
}
RavenBuffer::~RavenBuffer()
{
}
void RavenBuffer::Process(unsigned count, bool integrate, unsigned lp_shift)
{
if(integrate)
{
if(lp_shift != 0)
accum = ProcessLoop<0, true, 3, true, false, false>(count, accum, Buf(), NULL, NULL, lp_shift, 0, filter_state);
else
accum = ProcessLoop<0, true, 3, false, false, false>(count, accum, Buf(), NULL, NULL, lp_shift, 0);
}
else
{
if(lp_shift != 0)
accum = ProcessLoop<0, false, 0, true, false, false>(count, accum, Buf(), NULL, NULL, lp_shift, 0, filter_state);
else
accum = ProcessLoop<0, false, 0, false, false, false>(count, accum, Buf(), NULL, NULL, lp_shift, 0);
}
}
void RavenBuffer::Finish(unsigned count)
{
memmove(BB, &BB[count], OwlBuffer::HRBUF_OVERFLOW_PADDING * sizeof(BB[0]));
memset(&BB[OwlBuffer::HRBUF_OVERFLOW_PADDING], 0, count * sizeof(BB[0]));
}
static void kaiser_window( double* io, int count, double beta )
{
int const accuracy = 16; //12;
double* end = io + count;
double beta2 = beta * beta * (double) -0.25;
double to_fract = beta2 / ((double) count * count);
double i = 0;
double rescale = 0; // Doesn't need an initializer, to shut up gcc
for ( ; io < end; ++io, i += 1 )
{
double x = i * i * to_fract - beta2;
double u = x;
double k = x + 1;
double n = 2;
do
{
u *= x / (n * n);
n += 1;
k += u;
}
while ( k <= u * (1 << accuracy) );
if ( !i )
rescale = 1 / k; // otherwise values get large
*io *= k * rescale;
}
}
static void gen_sinc( double* out, int size, double cutoff, double kaiser )
{
assert( size % 2 == 0 ); // size must be enev
int const half_size = size / 2;
double* const mid = &out [half_size];
// Generate right half of sinc
for ( int i = 0; i < half_size; i++ )
{
double angle = (i * 2 + 1) * (M_PI / 2);
mid [i] = sin( angle * cutoff ) / angle;
}
kaiser_window( mid, half_size, kaiser );
// Mirror for left half
for ( int i = 0; i < half_size; i++ )
out [i] = mid [half_size - 1 - i];
}
static void normalize( double* io, int size, double gain = 1.0 )
{
double sum = 0;
for ( int i = 0; i < size; i++ )
sum += io [i];
double scale = gain / sum;
for ( int i = 0; i < size; i++ )
io [i] *= scale;
}
static INLINE void DoMAC(float *wave, float *coeffs, int32 count, int32 *accum_output)
{
float acc[4] = { 0, 0, 0, 0 };
for(int c = 0; MDFN_LIKELY(c < count); c += 4)
{
acc[0] += wave[c + 0] * coeffs[c + 0];
acc[1] += wave[c + 1] * coeffs[c + 1];
acc[2] += wave[c + 2] * coeffs[c + 2];
acc[3] += wave[c + 3] * coeffs[c + 3];
}
*accum_output = (acc[0] + acc[2]) + (acc[1] + acc[3]);
}
#ifdef ARCH_X86
#include "OwlResampler_x86.inc"
#endif
#ifdef ARCH_POWERPC_ALTIVEC
#include "OwlResampler_altivec.inc"
#endif
#ifdef __ARM_NEON__
#include "OwlResampler_neon.inc"
#endif
template<typename T, unsigned sa>
static T SDP2(T v)
{
T tmp;
tmp = (v >> ((sizeof(T) * 8) - 1)) & (((T)1 << sa) - 1);
return ((v + tmp) >> sa);
}
enum
{
SIMD_NONE = 0,
#ifdef ARCH_X86
SIMD_SSE_16X,
#ifdef HAVE_INLINEASM_AVX
SIMD_AVX_32X,
SIMD_AVX_32X_P16,
#else
#warning "Compiling without AVX inline assembly."
#endif
#elif defined(ARCH_POWERPC_ALTIVEC)
SIMD_ALTIVEC,
#elif defined __ARM_NEON__
SIMD_NEON
#endif
};
template<unsigned TA_SIMD_Type>
NO_INLINE int32 OwlResampler::T_Resample(OwlBuffer* in, const uint32 in_count, int16* out, const uint32 max_out_count, const bool reverse)
{
if(reverse)
{
int32* a = in->Buf();
int32* b = in->Buf() + in_count - 1;
while(MDFN_LIKELY(a < b))
{
std::swap<int32>(*a, *b);
a++;
b--;
}
}
//
//
//
uint32 count = 0;
int32* I32Out = &IntermediateBuffer[0];
const uint32 in_count_WLO = in->leftover + in_count;
const uint32 max = std::max<int64>(0, (int64)in_count_WLO - NumCoeffs);
uint32 InputPhase = in->InputPhase;
uint32 InputIndex = in->InputIndex;
OwlBuffer::I32_F_Pudding* InSamps = in->BufPudding() - in->leftover;
int32 leftover;
if(MDFN_UNLIKELY(InputPhase >= NumPhases))
{
fprintf(stderr, "[BUG] InputPhase >= NumPhases\n"); // Save states can also trigger this.
InputPhase = 0;
}
while(InputIndex < max)
{
float* wave = &InSamps[InputIndex].f;
float* coeffs = &PInfos[InputPhase].Coeffs[0];
int32 coeff_count = NumCoeffs;
switch(TA_SIMD_Type)
{
default:
case SIMD_NONE:
DoMAC(wave, coeffs, coeff_count, I32Out);
break;
#ifdef ARCH_X86
case SIMD_SSE_16X:
DoMAC_SSE_16X(wave, coeffs, coeff_count, I32Out);
break;
#ifdef HAVE_INLINEASM_AVX
case SIMD_AVX_32X:
DoMAC_AVX_32X(wave, coeffs, coeff_count, I32Out);
break;
case SIMD_AVX_32X_P16:
DoMAC_AVX_32X_P16(wave, coeffs, coeff_count, I32Out);
break;
#endif
#elif defined(ARCH_POWERPC_ALTIVEC)
case SIMD_ALTIVEC:
DoMAC_AltiVec(wave, coeffs, coeff_count, I32Out);
break;
#elif defined __ARM_NEON__
case SIMD_NEON:
DoMAC_NEON(wave, coeffs, coeff_count, I32Out);
break;
#endif
}
I32Out++;
count++;
InputPhase = PInfos[InputPhase].Next;
InputIndex += PInfos[InputPhase].Step;
}
#if defined(ARCH_X86) && defined(HAVE_INLINEASM_AVX)
if(TA_SIMD_Type == SIMD_AVX_32X || TA_SIMD_Type == SIMD_AVX_32X_P16)
{
asm volatile("vzeroupper\n\t" : : :
#if defined(__AVX__)
"ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7"
#if defined(__x86_64__)
, "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15"
#endif
#endif
);
}
#endif
if(InputIndex > in_count_WLO)
{
leftover = 0;
InputIndex -= in_count_WLO;
}
else
{
leftover = (int32)in_count_WLO - (int32)InputIndex;
InputIndex = 0;
}
#if 0
for(uint32 x = 0; x < count; x++)
{
int s = IntermediateBuffer[x] >> 8;
if(s < -32768 || s > 32767)
{
//printf("Flow: %6d\n", s);
if(s < -32768)
s = -32768;
else if(s > 32767)
s = 32767;
}
out[x * 2] = s;
}
#else
{
int64 debias = in->debias;
for(uint32 x = 0; x < count; x++)
{
int32 sample = IntermediateBuffer[x];
int32 s;
debias += (((int64)((uint64)(int64)sample << 16) - debias) * debias_multiplier) >> 16;
s = SDP2<int32, 8>(sample - (debias >> 16));
if(s < -32768 || s > 32767)
{
//printf("Flow: %6d\n", s);
if(s < -32768)
s = -32768;
else if(s > 32767)
s = 32767;
}
out[x * 2] = s;
}
in->debias = debias;
}
#endif
memmove(in->Buf() - leftover,
in->Buf() + in_count - leftover,
sizeof(int32) * (leftover + OwlBuffer::HRBUF_OVERFLOW_PADDING));
memset(in->Buf() + OwlBuffer::HRBUF_OVERFLOW_PADDING, 0, sizeof(int32) * in_count);
in->leftover = leftover;
in->InputPhase = InputPhase;
in->InputIndex = InputIndex;
return count;
}
void OwlResampler::ResetBufResampState(OwlBuffer* buf)
{
memset(buf->HRBuf, 0, sizeof(buf->HRBuf[0]) * OwlBuffer::HRBUF_LEFTOVER_PADDING);
buf->InputPhase = 0;
}
OwlResampler::~OwlResampler()
{
}
//
// Flush denormals, and coefficients that could lead to denormals, to zero.
//
static float FilterDenormal(float v)
{
union
{
float f;
uint32 i;
} cat_pun;
cat_pun.f = v;
if(((cat_pun.i >> 23) & 0xFF) <= 24) // Maybe < 24 is more correct?
{
MDFN_printf("Small FP coefficient detected: 0x%08x --- raw_sign=%d, raw_exp=0x%02x, raw_mantissa=0x%06x\n", cat_pun.i, cat_pun.i >> 31, (cat_pun.i >> 23) & 0xFF, cat_pun.i & ((1U << 23) - 1));
return(0);
}
return(v);
}
OwlResampler::OwlResampler(double input_rate, double output_rate, double rate_error, double debias_corner, int quality, double nyq_fudge)
{
std::unique_ptr<double[]> FilterBuf;
double ratio = (double)output_rate / input_rate;
double cutoff;
double required_bandwidth;
double k_beta;
double k_d;
for(int i = 0; i < 256; i++)
{
int a = SDP2<int32, 3>(i);
int b = SDP2<int32, 3>(-i);
int c = i / (1 << 3);
assert(a == -b && a == c);
}
assert(sizeof(OwlBuffer::I32_F_Pudding) == 4);
InputRate = input_rate;
OutputRate = output_rate;
RateError = rate_error;
DebiasCorner = debias_corner;
Quality = quality;
IntermediateBuffer.resize(OutputRate * 4 / 50); // *4 for safety padding, / min(50,60), an approximate calculation
const uint32 cpuext = 0; //cputest_get_flags();
MDFN_printf("OwlResampler.cpp debug info:\n");
//MDFN_indent(1);
// Get the number of phases required, and adjust ratio.
{
double s_ratio = (double)input_rate / output_rate;
double findo = 0;
uint32 count = 0;
uint32 findo_i;
do
{
count++;
findo += s_ratio;
} while( fabs(1.0 - ((floor(0.5 + findo) / count) / s_ratio)) > rate_error);
s_ratio = floor(0.5 + findo) / count;
findo_i = (uint32) floor(0.5 + findo);
ratio = 1 / s_ratio;
NumPhases = count;
PInfos.resize(NumPhases);
uint32 last_indoo = 0;
for(unsigned int i = 0; i < NumPhases; i++)
{
uint32 index_pos = i * findo_i / NumPhases;
PInfos[i].Next = (i + 1) % (NumPhases);
PInfos[i].Step = index_pos - last_indoo;
last_indoo = index_pos;
}
PInfos[0].Step = findo_i - last_indoo;
Ratio_Dividend = findo_i;
Ratio_Divisor = NumPhases;
MDFN_printf("Phases: %d, Output rate: %f, %d %d\n", NumPhases, input_rate * ratio, Ratio_Dividend, Ratio_Divisor);
MDFN_printf("Desired maximum rate error: %.10f, Actual rate error: %.10f\n", rate_error, fabs((double)input_rate / output_rate * ratio - 1));
}
static const struct
{
double beta;
double d;
double obw;
} QualityTable[7] =
{
{ 5.658, 3.62, 0.65 },
{ 6.764, 4.32, 0.70 },
{ 7.865, 5.00, 0.75 },
{ 8.960, 5.70, 0.80 },
{ 10.056, 6.40, 0.85 },
{ 10.056, 6.40, 0.90 },
{ 10.056, 6.40, 0.9333 }, // 1.0 - (6.40 / 96)
};
assert(quality >= 0 && quality <= 6);
k_beta = QualityTable[quality].beta;
k_d = QualityTable[quality].d;
//
// As far as filter frequency response design goes, we clamp the output rate parameter
// to keep PCE CD and PC-FX CD-DA sample amplitudes from going wild since we're not resampling CD-DA totally properly.
//
#define OWLRESAMP_FCALC_RATE_CLAMP 128000.0 //192000.0 //96000.0 //48000.0
// A little SOMETHING to widen the transition band a bit to reduce computational complexity with higher output rates.
const double something = std::min<double>(OWLRESAMP_FCALC_RATE_CLAMP, (48000.0 + std::min<double>(OWLRESAMP_FCALC_RATE_CLAMP, output_rate)) / 2 / QualityTable[quality].obw);
//
// Note: Cutoff calculation is performed again(though slightly differently) down below after the SIMD check.
//
cutoff = QualityTable[quality].obw * (std::min<double>(something, std::min<double>(input_rate, output_rate)) / input_rate);
required_bandwidth = (std::min<double>(OWLRESAMP_FCALC_RATE_CLAMP, std::min<double>(input_rate, output_rate)) / input_rate) - cutoff;
NumCoeffs = ceil(k_d / required_bandwidth);
MDFN_printf("Initial number of coefficients per phase: %u\n", NumCoeffs);
MDFN_printf("Initial nominal cutoff frequency: %f\n", InputRate * cutoff / 2);
//
// Put this lower limit BEFORE the SIMD stuff, otherwise the NumCoeffs calculation will be off.
//
if(NumCoeffs < 16)
NumCoeffs = 16;
if(0)
{
abort(); // The sky is falling AAAAAAAAAAAAA
}
#ifdef ARCH_X86
#ifdef HAVE_INLINEASM_AVX
else if((cpuext & CPUTEST_FLAG_AVX) && (NumCoeffs + 0xF) >= 32)
{
MDFN_printf("SIMD: AVX\n");
// AVX loop can't handle less than 32 MACs properly.
NumCoeffs = std::max<uint32>(32, NumCoeffs);
// Past 32 MACs, AVX loop granularity is 16 MACs(with some ugly maaaagic~)
NumCoeffs = (NumCoeffs + 0xF) &~ 0xF;
if(NumCoeffs & 0x10)
Resample_ = &OwlResampler::T_Resample<SIMD_AVX_32X_P16>;
else
Resample_ = &OwlResampler::T_Resample<SIMD_AVX_32X>;
}
#endif
else if(cpuext & CPUTEST_FLAG_SSE)
{
MDFN_printf("SIMD: SSE\n");
// SSE loop does 16 MACs per iteration.
NumCoeffs = (NumCoeffs + 0xF) &~ 0xF;
Resample_ = &OwlResampler::T_Resample<SIMD_SSE_16X>;
}
#endif
#ifdef ARCH_POWERPC_ALTIVEC
else if(1)
{
MDFN_printf("SIMD: AltiVec\n");
// AltiVec loop does 16 MACs per iteration.
NumCoeffs = (NumCoeffs + 0xF) &~ 0xF;
Resample_ = &OwlResampler::T_Resample<SIMD_ALTIVEC>;
}
#endif
#ifdef __ARM_NEON__
else if(1)
{
MDFN_printf("SIMD: NEON\n");
// NEON loop does 16 MACs per iteration.
NumCoeffs = (NumCoeffs + 0xF) &~ 0xF;
Resample_ = &OwlResampler::T_Resample<SIMD_NEON>;
}
#endif
else
{
// Default loop does 4 MACs per iteration.
NumCoeffs = (NumCoeffs + 3) &~ 3;
Resample_ = &OwlResampler::T_Resample<SIMD_NONE>;
}
//
// Don't alter NumCoeffs anymore from here on.
//
#if !defined(ARCH_X86) && !defined(ARCH_POWERPC_ALTIVEC) && !defined(__ARM_NEON__)
#warning "OwlResampler is being compiled without SIMD support."
#endif
//
// Adjust cutoff now that NumCoeffs may have been increased.
//
cutoff = std::min<double>(QualityTable[quality].obw * something / input_rate, (std::min<double>(input_rate, output_rate) / input_rate - ((double)k_d / NumCoeffs)));
cutoff *= nyq_fudge;
if(ceil(cutoff) > 1.0)
cutoff = 1.0;
MDFN_printf("Adjusted number of coefficients per phase: %u\n", NumCoeffs);
MDFN_printf("Adjusted nominal cutoff frequency: %f\n", InputRate * cutoff / 2);
assert(NumCoeffs <= OwlBuffer::HRBUF_LEFTOVER_PADDING);
CoeffsBuffer.resize((256 / sizeof(float)) + NumCoeffs * NumPhases);
for(unsigned int i = 0; i < NumPhases; i++)
PInfos[i].Coeffs = (float *)(((uintptr_t)&CoeffsBuffer[0] + 0xFF) &~ 0xFF) + (i * NumCoeffs);
MDFN_printf("Impulse response table memory usage: %zu bytes\n", CoeffsBuffer.size() * sizeof(float));
FilterBuf.reset(new double[NumCoeffs * NumPhases]);
gen_sinc(&FilterBuf[0], NumCoeffs * NumPhases, cutoff / NumPhases, k_beta);
normalize(&FilterBuf[0], NumCoeffs * NumPhases);
#if 0
for(int i = 0; i < NumCoeffs * NumPhases; i++)
fprintf(stderr, "%.20f\n", FilterBuf[i]);
#endif
for(unsigned int phase = 0; phase < NumPhases; phase++)
{
//double sum_d = 0;
//float sum_f4[4] = { 0, 0, 0, 0 };
const unsigned sp = (NumPhases - 1 - (((uint64)phase * Ratio_Dividend) % NumPhases));
const unsigned tp = phase;
for(unsigned int i = 0; i < NumCoeffs; i++)
{
double tmpcod = FilterBuf[i * NumPhases + sp] * NumPhases; // Tasty cod.
PInfos[tp].Coeffs[i] = FilterDenormal(tmpcod);
//sum_d += PInfos[tp].Coeffs[i];
//sum_f4[i % 4] += PInfos[tp].Coeffs[i];
}
#if 0
{
double sf4t = (sum_f4[0] + sum_f4[2]) + (sum_f4[1] + sum_f4[3]);
double sd_div_sf4t = sum_d / sf4t;
MDFN_printf("Phase %4u: sum_d=%.10f, sum_f4t=%.10f, sum_d div sum_f4t=%.10f(*65536=%f, dB=%.8f)\n", sp, sum_d, (double)sf4t, sd_div_sf4t, 65536.0 * sd_div_sf4t, fabs(20 * log10(sum_d / sf4t)));
}
#endif
}
assert(debias_corner < (output_rate / 16));
debias_multiplier = (uint32)(((uint64)1 << 16) * debias_corner / output_rate);
//MDFN_indent(-1);
//abort();
#if 0
{
static float dummy_wave[1024];
static float dummy_coeffs[1024];
int32 dummy_out;
uint32 begin_time = MDFND_GetTime();
for(int i = 0; i < 1024 * 1024; i++)
{
DoMAC_AVX_32X(dummy_wave, dummy_coeffs, 1024, &dummy_out);
//DoMAC_SSE_16X(dummy_wave, dummy_coeffs, 1024, &dummy_out);
}
printf("%u\n", MDFND_GetTime() - begin_time);
abort();
}
#endif
}

View File

@ -1,159 +0,0 @@
#ifndef __NES_FILTER_H
#define __NES_FILTER_H
#include <vector>
class OwlResampler;
class RavenBuffer;
struct StateMem;
class OwlBuffer
{
public:
enum { HRBUF_LEFTOVER_PADDING = 8192 };
enum { HRBUF_OVERFLOW_PADDING = 32 }; // For deltas and impulse responses and whatnot that are dangling off the end(>= final timestamp) sorta.
union I32_F_Pudding
{
int32 i32;
float f;
};
OwlBuffer();
~OwlBuffer();
INLINE int32* Buf(void)
{
return &HRBuf[HRBUF_LEFTOVER_PADDING].i32;
}
INLINE I32_F_Pudding* BufPudding(void)
{
return &HRBuf[HRBUF_LEFTOVER_PADDING];
}
void Integrate(unsigned count, unsigned lp_shift = 0, unsigned hp_shift = 0, RavenBuffer* mixin0 = NULL, RavenBuffer* mixin1 = NULL); // Convenience function.
void ResampleSkipped(unsigned count);
void ZeroLeftover(void);
private:
I32_F_Pudding HRBuf[HRBUF_LEFTOVER_PADDING + 65536 + HRBUF_OVERFLOW_PADDING];
int32 accum;
int64 filter_state[2];
//
// Resampler state:
//
int32 leftover;
// Index into the input buffer
uint32 InputIndex;
// Current input phase
uint32 InputPhase;
// DC bias removal filter thingy
int64 debias;
friend class OwlResampler;
};
class RavenBuffer
{
public:
RavenBuffer();
~RavenBuffer();
INLINE int32* Buf(void)
{
return &BB[0];
}
void Process(unsigned count, bool integrate = true, uint32 lp_shift = 0);
void Finish(unsigned count);
friend class OwlBuffer;
private:
int32 BB[65536 + OwlBuffer::HRBUF_OVERFLOW_PADDING];
int32 accum;
int64 filter_state[2];
};
class OwlResampler
{
public:
// Resamples from input_rate to output_rate, allowing for rate_error(output_rate +/- output_rate*rate_error)
// error in the resample ratio.
//
// debias_corner is the cheap high-pass DC bias removal filter coefficient. Higher values will result in more bias removal(and
// case a high-pass filter effect), while lower values will lower this effect. It should be <= output_rate / 64, to be on the safe side(prevent
// multiplication overflow). A value of 0 will disable its effect.
//
// quality is an arbitrary control of quality(0 for lowest quality, 5 for highest quality)
//
// nyq_fudge may be a tasty sleep drug.
//
OwlResampler(double input_rate, double output_rate, double rate_error, double debias_corner, int quality, double nyq_fudge = 1.0) MDFN_COLD;
OwlResampler(const OwlResampler &resamp) MDFN_COLD;
~OwlResampler() MDFN_COLD;
INLINE int32 Resample(OwlBuffer* in, const uint32 in_count, int16* out, const uint32 max_out_count, const bool reverse = false)
{
return (this->*OwlResampler::Resample_)(in, in_count, out, max_out_count, reverse);
}
void ResetBufResampState(OwlBuffer* buf);
// Get the InputRate / OutputRate ratio, expressed as a / b
void GetRatio(int32 *a, int32 *b)
{
*a = Ratio_Dividend;
*b = Ratio_Divisor;
}
private:
// Copy of the parameters passed to the constructor
double InputRate, OutputRate, RateError, DebiasCorner;
int Quality;
// Number of phases.
uint32 NumPhases;
uint32 NumPhases_Padded;
// Coefficients(in each phase, not total)
uint32 NumCoeffs;
struct PhaseInfo
{
// One pointer for each phase
float* Coeffs;
// In the FIR loop: InputPhase = PInfos[InputPhase].Next
uint32 Next;
// Incrementor for InputIndex. In the FIR loop, after updating InputPhase: InputIndex += PInfos[InputPhase].Step
uint32 Step;
};
std::vector<PhaseInfo> PInfos;
std::vector<float> CoeffsBuffer;
std::vector<int32> IntermediateBuffer; //int32 boobuf[8192];
template<unsigned TA_SIMD_Type>
int32 T_Resample(OwlBuffer* in, const uint32 in_count, int16* out, const uint32 max_out_count, const bool reverse);
int32 (OwlResampler::*Resample_)(OwlBuffer* in, const uint32 in_count, int16* out, const uint32 max_out_count, const bool reverse);
uint16 debias_multiplier;
// for GetRatio()
int32 Ratio_Dividend;
int32 Ratio_Divisor;
};
#endif

View File

@ -1,146 +0,0 @@
// Blip_Buffer 0.3.0. http://www.slack.net/~ant/nes-emu/
#include "Stereo_Buffer.h"
/* Library Copyright (C) 2004 Shay Green. Blip_Buffer 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.
Stereo_Buffer 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 Stereo_Buffer; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
Stereo_Buffer::Stereo_Buffer() {
stereo_added = false;
was_stereo = false;
}
Stereo_Buffer::~Stereo_Buffer() {
}
bool Stereo_Buffer::set_sample_rate( long rate, int msec )
{
for ( int i = 0; i < buf_count; i++ ) {
if ( bufs [i].set_sample_rate( rate, msec ) )
{
return false;
}
}
return true;
}
void Stereo_Buffer::clock_rate( long rate )
{
for ( int i = 0; i < buf_count; i++ )
bufs [i].clock_rate( rate );
}
void Stereo_Buffer::bass_freq( int bass )
{
for ( unsigned i = 0; i < buf_count; i++ )
bufs [i].bass_freq( bass );
}
void Stereo_Buffer::clear()
{
stereo_added = false;
was_stereo = false;
for ( int i = 0; i < buf_count; i++ )
bufs [i].clear();
}
void Stereo_Buffer::end_frame( blip_time_t clock_count, bool stereo )
{
for ( unsigned i = 0; i < buf_count; i++ )
{
bufs [i].end_frame( clock_count );
}
stereo_added |= stereo;
}
long Stereo_Buffer::read_samples( blip_sample_t* out, long max_samples )
{
long count = bufs [0].samples_avail();
if ( count > max_samples / 2 )
count = max_samples / 2;
if ( count )
{
if ( stereo_added || was_stereo )
{
mix_stereo( out, count );
bufs [0].remove_samples( count );
bufs [1].remove_samples( count );
bufs [2].remove_samples( count );
}
else
{
mix_mono( out, count );
bufs [0].remove_samples( count );
bufs [1].remove_silence( count );
bufs [2].remove_silence( count );
}
// to do: this might miss opportunities for optimization
if ( !bufs [0].samples_avail() ) {
was_stereo = stereo_added;
stereo_added = false;
}
}
return count * 2;
}
void Stereo_Buffer::mix_stereo( blip_sample_t* out, long count )
{
Blip_Reader l_left;
Blip_Reader l_right;
Blip_Reader l_center;
l_left.begin( bufs [1] );
l_right.begin( bufs [2] );
int bass = l_center.begin( bufs [0] );
while ( count-- )
{
int c = l_center.read();
out [0] = c + l_left.read();
out [1] = c + l_right.read();
out += 2;
l_center.next( bass );
l_left.next( bass );
l_right.next( bass );
}
l_center.end( bufs [0] );
l_right.end( bufs [2] );
l_left.end( bufs [1] );
}
void Stereo_Buffer::mix_mono( blip_sample_t* out, long count )
{
Blip_Reader in;
int bass = in.begin( bufs [0] );
while ( count-- )
{
int sample = in.read();
out [0] = sample;
out [1] = sample;
out += 2;
in.next( bass );
}
in.end( bufs [0] );
}

View File

@ -1,69 +0,0 @@
// Simple stereo Blip_Buffer for sound emulators whose oscillators output
// either on the left only, center, or right only.
// Blip_Buffer 0.3.0. Copyright (C) 2003-2004 Shay Green. GNU GPL license.
#ifndef STEREO_BUFFER_H
#define STEREO_BUFFER_H
#include "Blip_Buffer.h"
class Stereo_Buffer {
public:
Stereo_Buffer();
~Stereo_Buffer();
// Same as in Blip_Buffer (see Blip_Buffer.h)
bool set_sample_rate( long, int msec = 0 );
void clock_rate( long );
void bass_freq( int );
void clear();
// Buffers to output synthesis to
Blip_Buffer* left();
Blip_Buffer* center();
Blip_Buffer* right();
// Same as in Blip_Buffer. For more efficient operation, pass false
// for was_stereo if the left and right buffers had nothing added
// to them for this frame.
void end_frame( blip_time_t, bool was_stereo = true );
// Output is stereo with channels interleved, left before right. Counts
// are in samples, *not* pairs.
long samples_avail() const;
long read_samples( blip_sample_t*, long );
private:
// noncopyable
Stereo_Buffer( const Stereo_Buffer& );
Stereo_Buffer& operator = ( const Stereo_Buffer& );
enum { buf_count = 3 };
Blip_Buffer bufs [buf_count];
bool stereo_added;
bool was_stereo;
void mix_stereo( blip_sample_t*, long );
void mix_mono( blip_sample_t*, long );
};
inline Blip_Buffer* Stereo_Buffer::left() {
return &bufs [1];
}
inline Blip_Buffer* Stereo_Buffer::center() {
return &bufs [0];
}
inline Blip_Buffer* Stereo_Buffer::right() {
return &bufs [2];
}
inline long Stereo_Buffer::samples_avail() const {
return bufs [0].samples_avail();
}
#endif

View File

@ -1,677 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* soundbox.cpp:
** Copyright (C) 2006-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "pcfx.h"
#include "soundbox.h"
#include "king.h"
#include "cdrom/cdromif.h"
#include "cdrom/scsicd.h"
#include "pce_psg/pce_psg.h"
#include "sound/OwlResampler.h"
#include <math.h>
#include <string.h>
namespace MDFN_IEN_PCFX
{
static const int StepSizes[49] =
{
16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50,
55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157,
173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552};
static const int StepIndexDeltas[16] =
{
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8};
static OwlResampler *FXres = NULL;
static OwlBuffer *FXsbuf[2] = {NULL, NULL};
RavenBuffer *FXCDDABufs[2] = {NULL, NULL}; // Used in the CDROM code
static PCE_PSG *pce_psg = NULL;
static bool SoundEnabled;
static uint32 adpcm_lastts;
struct SoundBox
{
uint16 ADPCMControl;
uint8 ADPCMVolume[2][2]; // ADPCMVolume[channel(0 or 1)][left(0) or right(1)]
uint8 CDDAVolume[2];
int32 bigdiv;
int32 smalldiv;
int64 ResetAntiClick[2];
double VolumeFiltered[2][2];
double vf_xv[2][2][1 + 1], vf_yv[2][2][1 + 1];
int32 ADPCMDelta[2];
int32 ADPCMHaveDelta[2];
int32 ADPCMPredictor[2];
int32 StepSizeIndex[2];
uint32 ADPCMWhichNibble[2];
uint16 ADPCMHalfWord[2];
bool ADPCMHaveHalfWord[2];
int32 ADPCM_last[2][2];
};
static SoundBox sbox;
static double ADPCMVolTable[0x40];
static bool EmulateBuggyCodec; // If true, emulate the buggy codec/algorithm used by an official PC-FX ADPCM encoder, rather than how the
// hardware actually works.
static bool ResetAntiClickEnabled; // = true;
#ifdef WANT_DEBUGGER
enum
{
GSREG_ADPCM_CTRL = _PSG_GSREG_COUNT,
GSREG_ADPCM0_LVOL,
GSREG_ADPCM0_RVOL,
GSREG_ADPCM1_LVOL,
GSREG_ADPCM1_RVOL,
GSREG_ADPCM0_CUR,
GSREG_ADPCM1_CUR,
GSREG_CDDA_LVOL,
GSREG_CDDA_RVOL
};
#define CHPDMOO(n) \
{0, "--CH" #n "--:", "", 0xFFFF}, \
{PSG_GSREG_CH0_FREQ | (n << 8), "Freq", "PSG Ch" #n " Frequency(Period)", 2}, \
{PSG_GSREG_CH0_CTRL | (n << 8), "Ctrl", "PSG Ch" #n " Control", 1}, \
{PSG_GSREG_CH0_BALANCE | (n << 8), "Balance", "PSG Ch" #n " Balance", 1}, \
{PSG_GSREG_CH0_WINDEX | (n << 8), "WIndex", "PSG Ch" #n " Waveform Index", 1}, \
{ \
PSG_GSREG_CH0_SCACHE | (n << 8), "SCache", "PSG Ch" #n " Sample Cache", 1 \
}
static const RegType SBoxRegs[] =
{
{PSG_GSREG_SELECT, "Select", "PSG Channel Select", 1},
{PSG_GSREG_GBALANCE, "GBal", "PSG Global Balance", 1},
{PSG_GSREG_LFOFREQ, "LFOFreq", "PSG LFO Freq", 1},
{PSG_GSREG_LFOCTRL, "LFOCtrl", "PSG LFO Control", 1},
CHPDMOO(0),
CHPDMOO(1),
CHPDMOO(2),
CHPDMOO(3),
CHPDMOO(4),
{PSG_GSREG_CH4_NCTRL, "NCtrl", "PSG Ch4 Noise Control", 1},
{PSG_GSREG_CH4_LFSR, "LFSR", "PSG Ch4 Noise LFSR", 0x100 | 18},
CHPDMOO(5),
{PSG_GSREG_CH5_NCTRL, "NCtrl", "PSG Ch5 Noise Control", 1},
{PSG_GSREG_CH5_LFSR, "LFSR", "PSG Ch5 Noise LFSR", 0x100 | 18},
{0, "--ADPCM:--", "", 0xFFFF},
{GSREG_ADPCM_CTRL, "Ctrl", "ADPCM Control", 2},
{GSREG_ADPCM0_LVOL, "CH0LVol", "ADPCM Ch0 Left Volume", 1},
{GSREG_ADPCM0_RVOL, "CH0RVol", "ADPCM Ch0 Right Volume", 1},
{GSREG_ADPCM1_LVOL, "CH1LVol", "ADPCM Ch1 Left Volume", 1},
{GSREG_ADPCM1_RVOL, "CH1RVol", "ADPCM Ch1 Right Volume", 1},
{GSREG_ADPCM0_CUR, "CH0Prc", "ADPCM Ch0 Predictor Value", 2},
{GSREG_ADPCM1_CUR, "CH1Prc", "ADPCM Ch1 Predictor Value", 2},
{0, "--CD-DA:--", "", 0xFFFF},
{GSREG_CDDA_LVOL, "CDLVol", "CD-DA Left Volume", 1},
{GSREG_CDDA_RVOL, "CDRVol", "CD-DA Right Volume", 1},
{0, "", "", 0},
};
static uint32 SBoxDBG_GetRegister(const unsigned int id, char *special, const uint32 special_len)
{
uint32 value = 0xDEADBEEF;
switch (id)
{
case GSREG_ADPCM_CTRL:
value = sbox.ADPCMControl;
if (special)
{
int tmp_freq = 32 / (1 << (value & 0x3));
trio_snprintf(special, special_len, "Frequency: ~%dKHz, Ch0 Interpolation: %s, Ch1 Interpolation: %s, Ch0 Reset: %d, Ch1 Reset: %d", tmp_freq, (value & 0x4) ? "On" : "Off", (value & 0x8) ? "On" : "Off",
(int)(bool)(value & 0x10), (int)(bool)(value & 0x20));
}
break;
case GSREG_ADPCM0_LVOL:
value = sbox.ADPCMVolume[0][0];
break;
case GSREG_ADPCM0_RVOL:
value = sbox.ADPCMVolume[0][1];
break;
case GSREG_ADPCM1_LVOL:
value = sbox.ADPCMVolume[1][0];
break;
case GSREG_ADPCM1_RVOL:
value = sbox.ADPCMVolume[1][1];
break;
case GSREG_CDDA_LVOL:
value = sbox.CDDAVolume[0];
break;
case GSREG_CDDA_RVOL:
value = sbox.CDDAVolume[1];
break;
case GSREG_ADPCM0_CUR:
value = sbox.ADPCMPredictor[0] + 0x4000;
break;
case GSREG_ADPCM1_CUR:
value = sbox.ADPCMPredictor[1] + 0x4000;
break;
default:
value = pce_psg->GetRegister(id, special, special_len);
break;
}
return (value);
}
static void SBoxDBG_SetRegister(const unsigned int id, uint32 value)
{
if (id < _PSG_GSREG_COUNT)
pce_psg->SetRegister(id, value);
else
switch (id)
{
case GSREG_ADPCM_CTRL:
sbox.ADPCMControl = value & 0xFFFF;
break;
case GSREG_ADPCM0_LVOL:
sbox.ADPCMVolume[0][0] = value & 0x3F;
break;
case GSREG_ADPCM0_RVOL:
sbox.ADPCMVolume[0][1] = value & 0x3F;
break;
case GSREG_ADPCM1_LVOL:
sbox.ADPCMVolume[1][0] = value & 0x3F;
break;
case GSREG_ADPCM1_RVOL:
sbox.ADPCMVolume[1][1] = value & 0x3F;
break;
case GSREG_CDDA_LVOL:
sbox.CDDAVolume[0] = value & 0x3F;
SCSICD_SetCDDAVolume(0.50f * sbox.CDDAVolume[0] / 63, 0.50f * sbox.CDDAVolume[1] / 63);
break;
case GSREG_CDDA_RVOL:
sbox.CDDAVolume[1] = value & 0x3F;
SCSICD_SetCDDAVolume(0.50f * sbox.CDDAVolume[0] / 63, 0.50f * sbox.CDDAVolume[1] / 63);
break;
case GSREG_ADPCM0_CUR:
sbox.ADPCMPredictor[0] = ((int32)value & 0x7FFF) - 0x4000;
break;
case GSREG_ADPCM1_CUR:
sbox.ADPCMPredictor[1] = ((int32)value & 0x7FFF) - 0x4000;
break;
}
}
static const RegGroupType SBoxRegsGroup =
{
"SndBox",
SBoxRegs,
SBoxDBG_GetRegister,
SBoxDBG_SetRegister};
#endif
static void RedoVolume(void)
{
pce_psg->SetVolume(0.681); //0.227 * 0.50);
//ADPCMSynth.volume(0.50);
}
bool SoundBox_SetSoundRate(uint32 rate)
{
SoundEnabled = (bool)rate;
if (FXres)
{
delete FXres;
FXres = NULL;
}
if (rate > 0)
{
FXres = new OwlResampler(PCFX_MASTER_CLOCK / 12, rate, Setting_ResampRateError, 20, Setting_ResampQuality);
for (unsigned i = 0; i < 2; i++)
FXres->ResetBufResampState(FXsbuf[i]);
}
RedoVolume();
return (TRUE);
}
void SoundBox_Init(bool arg_EmulateBuggyCodec, bool arg_ResetAntiClickEnabled)
{
adpcm_lastts = 0;
SoundEnabled = false;
EmulateBuggyCodec = arg_EmulateBuggyCodec;
ResetAntiClickEnabled = arg_ResetAntiClickEnabled;
for (unsigned i = 0; i < 2; i++)
{
FXsbuf[i] = new OwlBuffer();
FXCDDABufs[i] = new RavenBuffer();
}
pce_psg = new PCE_PSG(FXsbuf[0]->Buf(), FXsbuf[1]->Buf(), PCE_PSG::REVISION_HUC6280A);
#ifdef WANT_DEBUGGER
MDFNDBG_AddRegGroup(&SBoxRegsGroup);
#endif
memset(&sbox, 0, sizeof(sbox));
// Build ADPCM volume table, 1.5dB per step, ADPCM volume settings of 0x0 through 0x1B result in silence.
for (int x = 0; x < 0x40; x++)
{
double flub = 1;
int vti = 0x3F - x;
if (x)
flub /= pow(2, (double)1 / 4 * x);
if (vti <= 0x1B)
ADPCMVolTable[vti] = 0;
else
ADPCMVolTable[vti] = flub;
}
}
/* Macro to access currently selected PSG channel */
void SoundBox_Write(uint32 A, uint16 V, const v810_timestamp_t timestamp)
{
A &= 0x3F;
if (A < 0x20)
{
pce_psg->Write(timestamp / 3, A >> 1, V);
}
else
{
//printf("%04x %04x %d\n", A, V, timestamp);
switch (A & 0x3F)
{
//default: printf("HARUM: %04x %04x\n", A, V); break;
case 0x20:
SoundBox_ADPCMUpdate(timestamp);
for (int ch = 0; ch < 2; ch++)
{
if (!(sbox.ADPCMControl & (0x10 << ch)) && (V & (0x10 << ch)))
{
//printf("Reset: %d\n", ch);
if (ResetAntiClickEnabled)
{
sbox.ResetAntiClick[ch] += (int64)((uint64)sbox.ADPCMPredictor[ch] << 32);
if (sbox.ResetAntiClick[ch] > ((int64)0x3FFF << 32))
sbox.ResetAntiClick[ch] = (int64)0x3FFF << 32;
if (sbox.ResetAntiClick[ch] < -((int64)0x4000 << 32))
sbox.ResetAntiClick[ch] = -((int64)0x4000 << 32);
}
sbox.ADPCMPredictor[ch] = 0;
sbox.StepSizeIndex[ch] = 0;
}
}
sbox.ADPCMControl = V;
break;
case 0x22:
SoundBox_ADPCMUpdate(timestamp);
sbox.ADPCMVolume[0][0] = V & 0x3F;
break;
case 0x24:
SoundBox_ADPCMUpdate(timestamp);
sbox.ADPCMVolume[0][1] = V & 0x3F;
break;
case 0x26:
SoundBox_ADPCMUpdate(timestamp);
sbox.ADPCMVolume[1][0] = V & 0x3F;
break;
case 0x28:
SoundBox_ADPCMUpdate(timestamp);
sbox.ADPCMVolume[1][1] = V & 0x3F;
break;
case 0x2A:
sbox.CDDAVolume[0] = V & 0x3F;
SCSICD_SetCDDAVolume(0.50f * sbox.CDDAVolume[0] / 63, 0.50f * sbox.CDDAVolume[1] / 63);
break;
case 0x2C:
sbox.CDDAVolume[1] = V & 0x3F;
SCSICD_SetCDDAVolume(0.50f * sbox.CDDAVolume[0] / 63, 0.50f * sbox.CDDAVolume[1] / 63);
break;
}
}
}
static uint32 KINGADPCMControl;
void SoundBox_SetKINGADPCMControl(uint32 value)
{
KINGADPCMControl = value;
}
/* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
Command line: /www/usr/fisher/helpers/mkfilter -Bu -Lp -o 1 -a 1.5888889125e-04 0.0000000000e+00 -l */
static void DoVolumeFilter(int ch, int lr)
{
sbox.vf_xv[ch][lr][0] = sbox.vf_xv[ch][lr][1];
sbox.vf_xv[ch][lr][1] = (double)ADPCMVolTable[sbox.ADPCMVolume[ch][lr]] / 2.004348738e+03;
sbox.vf_yv[ch][lr][0] = sbox.vf_yv[ch][lr][1];
sbox.vf_yv[ch][lr][1] = (sbox.vf_xv[ch][lr][0] + sbox.vf_xv[ch][lr][1]) + (0.9990021696 * sbox.vf_yv[ch][lr][0]);
sbox.VolumeFiltered[ch][lr] = sbox.vf_yv[ch][lr][1];
}
static const int16 ADPCM_PhaseFilter[8][7] =
{
/* 0 */ {40, 283, 654, 683, 331, 56, 1}, // 2048
/* 1 */ {28, 238, 618, 706, 381, 75, 2}, // 2048
/* 2 */ {19, 197, 577, 720, 432, 99, 4}, // 2048
/* 3 */ {12, 160, 532, 726, 483, 128, 7}, // 2048
/* 4 */ {7, 128, 483, 726, 532, 160, 12}, // 2048
/* 5 */ {4, 99, 432, 720, 577, 197, 19}, // 2048
/* 6 */ {2, 75, 381, 706, 618, 238, 28}, // 2048
/* 7 */ {1, 56, 331, 683, 654, 283, 40}, // 2048
};
v810_timestamp_t SoundBox_ADPCMUpdate(const v810_timestamp_t timestamp)
{
int32 run_time = timestamp - adpcm_lastts;
adpcm_lastts = timestamp;
sbox.bigdiv -= run_time * 2;
while (sbox.bigdiv <= 0)
{
sbox.smalldiv--;
while (sbox.smalldiv <= 0)
{
sbox.smalldiv += 1 << ((KINGADPCMControl >> 2) & 0x3);
for (int ch = 0; ch < 2; ch++)
{
// Keep playing our last halfword fetched even if KING ADPCM is disabled
if (sbox.ADPCMHaveHalfWord[ch] || KINGADPCMControl & (1 << ch))
{
if (!sbox.ADPCMWhichNibble[ch])
{
sbox.ADPCMHalfWord[ch] = KING_GetADPCMHalfWord(ch);
sbox.ADPCMHaveHalfWord[ch] = TRUE;
}
// If the channel's reset bit is set, don't update its ADPCM state.
if (sbox.ADPCMControl & (0x10 << ch))
{
sbox.ADPCMDelta[ch] = 0;
}
else
{
uint8 nibble = (sbox.ADPCMHalfWord[ch] >> (sbox.ADPCMWhichNibble[ch])) & 0xF;
int32 BaseStepSize = StepSizes[sbox.StepSizeIndex[ch]];
//if(!ch)
//printf("Nibble: %02x\n", nibble);
if (EmulateBuggyCodec)
{
if (BaseStepSize == 1552)
BaseStepSize = 1522;
sbox.ADPCMDelta[ch] = BaseStepSize * ((nibble & 0x7) + 1) * 2;
}
else
sbox.ADPCMDelta[ch] = BaseStepSize * ((nibble & 0x7) + 1);
// Linear interpolation turned on?
if (sbox.ADPCMControl & (0x4 << ch))
sbox.ADPCMDelta[ch] >>= (KINGADPCMControl >> 2) & 0x3;
if (nibble & 0x8)
sbox.ADPCMDelta[ch] = -sbox.ADPCMDelta[ch];
sbox.StepSizeIndex[ch] += StepIndexDeltas[nibble];
if (sbox.StepSizeIndex[ch] < 0)
sbox.StepSizeIndex[ch] = 0;
if (sbox.StepSizeIndex[ch] > 48)
sbox.StepSizeIndex[ch] = 48;
}
sbox.ADPCMHaveDelta[ch] = 1;
// Linear interpolation turned on?
if (sbox.ADPCMControl & (0x4 << ch))
sbox.ADPCMHaveDelta[ch] = 1 << ((KINGADPCMControl >> 2) & 0x3);
sbox.ADPCMWhichNibble[ch] = (sbox.ADPCMWhichNibble[ch] + 4) & 0xF;
if (!sbox.ADPCMWhichNibble[ch])
sbox.ADPCMHaveHalfWord[ch] = FALSE;
}
} // for(int ch...)
} // while(sbox.smalldiv <= 0)
const uint32 synthtime42 = (timestamp << 1) + sbox.bigdiv;
const uint32 synthtime14 = synthtime42 / 3;
const uint32 synthtime = synthtime14 >> 3;
const unsigned synthtime_phase = synthtime14 & 7;
//printf("Phase: %d, %d\n", synthtime42 % 24, (synthtime42 / 3) & 7);
for (int ch = 0; ch < 2; ch++)
{
//if(!ch)
//{
// printf("%d\n", synthtime - last_synthtime);
// last_synthtime = synthtime;
//}
if (sbox.ADPCMHaveDelta[ch])
{
sbox.ADPCMPredictor[ch] += sbox.ADPCMDelta[ch];
sbox.ADPCMHaveDelta[ch]--;
if (sbox.ADPCMPredictor[ch] > 0x3FFF)
{
sbox.ADPCMPredictor[ch] = 0x3FFF; /*printf("Overflow: %d\n", ch);*/
}
if (sbox.ADPCMPredictor[ch] < -0x4000)
{
sbox.ADPCMPredictor[ch] = -0x4000; /*printf("Underflow: %d\n", ch);*/
}
}
else
{
}
if (SoundEnabled)
{
int32 samp[2];
if (EmulateBuggyCodec)
{
samp[0] = (int32)(((sbox.ADPCMPredictor[ch] >> 1) + (sbox.ResetAntiClick[ch] >> 33)) * sbox.VolumeFiltered[ch][0]);
samp[1] = (int32)(((sbox.ADPCMPredictor[ch] >> 1) + (sbox.ResetAntiClick[ch] >> 33)) * sbox.VolumeFiltered[ch][1]);
}
else
{
samp[0] = (int32)((sbox.ADPCMPredictor[ch] + (sbox.ResetAntiClick[ch] >> 32)) * sbox.VolumeFiltered[ch][0]);
samp[1] = (int32)((sbox.ADPCMPredictor[ch] + (sbox.ResetAntiClick[ch] >> 32)) * sbox.VolumeFiltered[ch][1]);
}
#if 0
printf("%d, %f %f\n", ch, sbox.VolumeFiltered[ch][0], sbox.VolumeFiltered[ch][1]);
{
static int inv = 0x1FFF;
samp[0] = samp[1] = inv;
if(ch == 1)
inv = -inv;
}
#endif
for (unsigned y = 0; y < 2; y++)
{
const int32 delta = samp[y] - sbox.ADPCM_last[ch][y];
int32 *tb = FXsbuf[y]->Buf() + (synthtime & 0xFFFF);
const int16 *coeffs = ADPCM_PhaseFilter[synthtime_phase];
for (unsigned c = 0; c < 7; c++)
{
int32 tmp = delta * coeffs[c];
tb[c] += tmp;
}
}
sbox.ADPCM_last[ch][0] = samp[0];
sbox.ADPCM_last[ch][1] = samp[1];
}
}
for (int ch = 0; ch < 2; ch++)
{
sbox.ResetAntiClick[ch] -= sbox.ResetAntiClick[ch] >> 8;
//if(ch)
// MDFN_DispMessage("%d", (int)(sbox.ResetAntiClick[ch] >> 32));
}
for (int ch = 0; ch < 2; ch++)
for (int lr = 0; lr < 2; lr++)
{
DoVolumeFilter(ch, lr);
}
sbox.bigdiv += 1365 * 2 / 2;
}
return (timestamp + (sbox.bigdiv + 1) / 2);
}
int32 SoundBox_Flush(const v810_timestamp_t end_timestamp, v810_timestamp_t *new_base_timestamp, int16 *SoundBuf, const int32 MaxSoundFrames, const bool reverse)
{
const uint32 end_timestamp_div3 = end_timestamp / 3;
const uint32 end_timestamp_div12 = end_timestamp / 12;
const uint32 end_timestamp_mod12 = end_timestamp % 12;
const unsigned rsc = std::min<unsigned>(65536, end_timestamp_div12);
int32 FrameCount = 0;
*new_base_timestamp = end_timestamp_mod12;
pce_psg->Update(end_timestamp_div3);
for (unsigned y = 0; y < 2; y++)
{
if (SoundEnabled && FXres)
{
FXsbuf[y]->Integrate(rsc, 0, 0, FXCDDABufs[y]);
FrameCount = FXres->Resample(FXsbuf[y], rsc, SoundBuf + y, MaxSoundFrames, reverse);
}
else
FXsbuf[y]->ResampleSkipped(rsc);
FXCDDABufs[y]->Finish(rsc);
}
return (FrameCount);
}
void SoundBox_ResetTS(const v810_timestamp_t ts_base)
{
pce_psg->ResetTS(ts_base / 3);
adpcm_lastts = ts_base;
}
void SoundBox_Reset(const v810_timestamp_t timestamp)
{
SoundBox_ADPCMUpdate(timestamp);
pce_psg->Power(timestamp / 3);
sbox.ADPCMControl = 0;
memset(&sbox.vf_xv, 0, sizeof(sbox.vf_xv));
memset(&sbox.vf_yv, 0, sizeof(sbox.vf_yv));
for (int lr = 0; lr < 2; lr++)
{
for (int ch = 0; ch < 2; ch++)
{
sbox.ADPCMVolume[ch][lr] = 0;
sbox.VolumeFiltered[ch][lr] = 0;
}
sbox.CDDAVolume[lr] = 0;
}
for (int ch = 0; ch < 2; ch++)
{
sbox.ADPCMPredictor[ch] = 0;
sbox.StepSizeIndex[ch] = 0;
}
memset(sbox.ADPCMWhichNibble, 0, sizeof(sbox.ADPCMWhichNibble));
memset(sbox.ADPCMHalfWord, 0, sizeof(sbox.ADPCMHalfWord));
memset(sbox.ADPCMHaveHalfWord, 0, sizeof(sbox.ADPCMHaveHalfWord));
SCSICD_SetCDDAVolume(0.50f * sbox.CDDAVolume[0] / 63, 0.50f * sbox.CDDAVolume[1] / 63);
sbox.bigdiv = 2; // TODO: KING->SBOX ADPCM Synch //(1365 - 85 * 4) * 2; //1365 * 2 / 2;
sbox.smalldiv = 0;
}
}

View File

@ -1,45 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* soundbox.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _PCFX_SOUNDBOX_H
#define _PCFX_SOUNDBOX_H
namespace MDFN_IEN_PCFX
{
bool SoundBox_SetSoundRate(uint32 rate);
int32 SoundBox_Flush(const v810_timestamp_t timestamp, v810_timestamp_t* new_base_timestamp, int16 *SoundBuf, const int32 MaxSoundFrames, const bool reverse);
void SoundBox_Write(uint32 A, uint16 V, const v810_timestamp_t timestamp);
void SoundBox_Init(bool arg_EmulateBuggyCodec, bool arg_ResetAntiClickEnabled) MDFN_COLD;
void SoundBox_Reset(const v810_timestamp_t timestamp) MDFN_COLD;
void SoundBox_SetKINGADPCMControl(uint32);
v810_timestamp_t SoundBox_ADPCMUpdate(const v810_timestamp_t timestamp);
void SoundBox_ResetTS(const v810_timestamp_t ts_base);
}
#include "sound/Blip_Buffer.h"
#include "sound/Stereo_Buffer.h"
#endif

View File

@ -1,175 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* timer.cpp:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
TODO: Determine if the interrupt request bit can be manually set even if timer enable and/or timer int enable bits are 0.
*/
#include "pcfx.h"
#include "interrupt.h"
#include "timer.h"
namespace MDFN_IEN_PCFX
{
static uint16 control;
static uint16 period;
static int32 counter;
static int32 lastts;
static INLINE v810_timestamp_t CalcNextEventTS(const v810_timestamp_t timestamp)
{
return((control & 0x2) ? (timestamp + counter) : PCFX_EVENT_NONONO);
}
#define EFF_PERIOD ((period ? period : 0x10000) * 15)
v810_timestamp_t FXTIMER_Update(const v810_timestamp_t timestamp)
{
if(control & 0x2)
{
int32 cycles = timestamp - lastts;
counter -= cycles;
while(counter <= 0)
{
counter += EFF_PERIOD;
if(control & 0x1)
{
control |= 0x4;
PCFXIRQ_Assert(PCFXIRQ_SOURCE_TIMER, TRUE);
}
}
}
lastts = timestamp;
return(CalcNextEventTS(timestamp));
}
void FXTIMER_ResetTS(int32 ts_base)
{
lastts = ts_base;
}
uint16 FXTIMER_Read16(uint32 A, const v810_timestamp_t timestamp)
{
FXTIMER_Update(timestamp);
switch(A & 0xFC0)
{
default: return(0);
case 0xF00: return(control);
case 0xF80: return(period);
case 0xFC0: return((counter + 14) / 15);
}
return(0);
}
uint8 FXTIMER_Read8(uint32 A, const v810_timestamp_t timestamp)
{
FXTIMER_Update(timestamp);
return(FXTIMER_Read16(A&~1, timestamp) >> ((A & 1) * 8));
}
void FXTIMER_Write16(uint32 A, uint16 V, const v810_timestamp_t timestamp)
{
FXTIMER_Update(timestamp);
switch(A & 0xFC0)
{
default: break;
case 0xF00: if(!(control & 0x2) && (V & 0x2))
counter = EFF_PERIOD;
control = V & 0x7;
if(V & 0x4)
FXDBG("Timer control write with D2 set?");
PCFXIRQ_Assert(PCFXIRQ_SOURCE_TIMER, (bool)(control & 0x4));
PCFX_SetEvent(PCFX_EVENT_TIMER, CalcNextEventTS(timestamp));
break;
case 0xF80: period = V;
PCFX_SetEvent(PCFX_EVENT_TIMER, CalcNextEventTS(timestamp));
break;
}
}
uint32 FXTIMER_GetRegister(const unsigned int id, char *special, const uint32 special_len)
{
uint32 value = 0xDEADBEEF;
switch(id)
{
case FXTIMER_GSREG_TCTRL:
value = control;
if(special)
{
trio_snprintf(special, special_len, "Counting Enabled: %d, IRQ Enabled: %d, IRQ Asserted: %d", (int)(bool)(control & 2), (int)(bool)(control & 1), (int)(bool)(control & 4));
}
break;
case FXTIMER_GSREG_TPRD:
value = period;
if(special)
{
trio_snprintf(special, special_len, "Effective Period: %d; 21477272 / %d = %fHz", EFF_PERIOD, EFF_PERIOD, (double)21477272 / (EFF_PERIOD));
}
break;
case FXTIMER_GSREG_TCNTR:
value = counter;
if(special)
{
//trio_snprintf(buf, 256, "Pad: %d, ??: %d, Timer: %d, Reset: %d",
//*special = std::string(buf);
}
break;
}
return value;
}
void FXTIMER_SetRegister(const unsigned int id, uint32 value)
{
}
void FXTIMER_Reset(void)
{
control = 0;
period = 0;
counter = 0;
}
void FXTIMER_Init(void)
{
lastts = 0;
FXTIMER_Reset();
}
}

View File

@ -1,49 +0,0 @@
/******************************************************************************/
/* Mednafen NEC PC-FX Emulation Module */
/******************************************************************************/
/* timer.h:
** Copyright (C) 2006-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PCFX_TIMER_H
#define __PCFX_TIMER_H
namespace MDFN_IEN_PCFX
{
void FXTIMER_Write16(uint32 A, uint16 V, const v810_timestamp_t timestamp);
uint16 FXTIMER_Read16(uint32 A, const v810_timestamp_t timestamp);
uint8 FXTIMER_Read8(uint32 A, const v810_timestamp_t timestamp);
v810_timestamp_t FXTIMER_Update(const v810_timestamp_t timestamp);
void FXTIMER_ResetTS(int32 ts_base);
void FXTIMER_Reset(void) MDFN_COLD;
void FXTIMER_Init(void) MDFN_COLD;
enum
{
FXTIMER_GSREG_TCTRL = 0,
FXTIMER_GSREG_TPRD,
FXTIMER_GSREG_TCNTR
};
uint32 FXTIMER_GetRegister(const unsigned int id, char *special, const uint32 special_len);
void FXTIMER_SetRegister(const unsigned int id, uint32 value);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,360 +0,0 @@
////////////////////////////////////////////////////////////////
// Defines for the V810 CPU
#ifndef V810_CPU_H_
#define V810_CPU_H_
#include <vector>
#include "v810_fp_ops.h"
typedef int32 v810_timestamp_t;
#define V810_FAST_MAP_SHIFT 16
#define V810_FAST_MAP_PSIZE (1 << V810_FAST_MAP_SHIFT)
#define V810_FAST_MAP_TRAMPOLINE_SIZE 1024
// Exception codes
enum
{
ECODE_TRAP_BASE = 0xFFA0,
ECODE_INVALID_OP = 0xFF90,
ECODE_ZERO_DIV = 0xFF80, // Integer divide by 0
ECODE_FIV = 0xFF70, // Floating point invalid operation
ECODE_FZD = 0xFF68, // Floating point zero division
ECODE_FOV = 0xFF64, // Floating point overflow
//#define ECODE_FUD 0xFF62 // Floating point underflow(unused on V810)
//#define ECODE_FPR 0xFF61 // Floating point precision degradation(unused on V810)
ECODE_FRO = 0xFF60 // Floating point reserved operand
};
enum
{
INVALID_OP_HANDLER_ADDR = 0xFFFFFF90, // Invalid opcode/instruction code!
ZERO_DIV_HANDLER_ADDR = 0xFFFFFF80, // Integer divide by 0 exception
FPU_HANDLER_ADDR = 0xFFFFFF60, // FPU exception
TRAP_HANDLER_BASE = 0xFFFFFFA0 // TRAP instruction
};
//System Register Defines (these are the only valid system registers!)
#define EIPC 0 //Exeption/Interupt PC
#define EIPSW 1 //Exeption/Interupt PSW
#define FEPC 2 //Fatal Error PC
#define FEPSW 3 //Fatal Error PSW
#define ECR 4 //Exception Cause Register
#define PSW 5 //Program Status Word
#define PIR 6 //Processor ID Register
#define TKCW 7 //Task Controll Word
#define CHCW 24 //Cashe Controll Word
#define ADDTRE 25 //ADDTRE
//PSW Specifics
#define PSW_IA 0xF0000 // All Interupt bits...
#define PSW_I3 0x80000
#define PSW_I2 0x40000
#define PSW_I1 0x20000
#define PSW_I0 0x10000
#define PSW_NP 0x08000
#define PSW_EP 0x04000
#define PSW_AE 0x02000
#define PSW_ID 0x01000
#define PSW_FRO 0x00200 // Floating point reserved operand(set on denormal, NaN, or indefinite)
#define PSW_FIV 0x00100 // Floating point invalid operation(set when trying to convert a number too large to an (un)signed integer)
#define PSW_FZD 0x00080 // Floating point divide by zero
#define PSW_FOV 0x00040 // Floating point overflow
#define PSW_FUD 0x00020 // Floating point underflow
#define PSW_FPR 0x00010 // Floating point precision degradation
#define PSW_CY 0x00008
#define PSW_OV 0x00004
#define PSW_S 0x00002
#define PSW_Z 0x00001
//condition codes
#define COND_V 0
#define COND_C 1
#define COND_Z 2
#define COND_NH 3
#define COND_S 4
#define COND_T 5
#define COND_LT 6
#define COND_LE 7
#define COND_NV 8
#define COND_NC 9
#define COND_NZ 10
#define COND_H 11
#define COND_NS 12
#define COND_F 13
#define COND_GE 14
#define COND_GT 15
#define TESTCOND_V (S_REG[PSW]&PSW_OV)
#define TESTCOND_L (S_REG[PSW]&PSW_CY)
#define TESTCOND_C TESTCOND_L
#define TESTCOND_E (S_REG[PSW]&PSW_Z)
#define TESTCOND_Z TESTCOND_E
#define TESTCOND_NH ( (S_REG[PSW]&PSW_Z) || (S_REG[PSW]&PSW_CY) )
#define TESTCOND_N (S_REG[PSW]&PSW_S)
#define TESTCOND_S TESTCOND_N
#define TESTCOND_LT ( (!!(S_REG[PSW]&PSW_S)) ^ (!!(S_REG[PSW]&PSW_OV)) )
#define TESTCOND_LE ( ((!!(S_REG[PSW]&PSW_S)) ^ (!!(S_REG[PSW]&PSW_OV))) || (S_REG[PSW]&PSW_Z) )
#define TESTCOND_NV (!(S_REG[PSW]&PSW_OV))
#define TESTCOND_NL (!(S_REG[PSW]&PSW_CY))
#define TESTCOND_NC TESTCOND_NL
#define TESTCOND_NE (!(S_REG[PSW]&PSW_Z))
#define TESTCOND_NZ TESTCOND_NE
#define TESTCOND_H ( !((S_REG[PSW]&PSW_Z) || (S_REG[PSW]&PSW_CY)) )
#define TESTCOND_P (!(S_REG[PSW] & PSW_S))
#define TESTCOND_NS TESTCOND_P
#define TESTCOND_GE (!((!!(S_REG[PSW]&PSW_S))^(!!(S_REG[PSW]&PSW_OV))))
#define TESTCOND_GT (! (((!!(S_REG[PSW]&PSW_S))^(!!(S_REG[PSW]&PSW_OV))) || (S_REG[PSW]&PSW_Z)) )
// Tag layout
// Bit 0-21: TAG31-TAG10
// Bit 22-23: Validity bits(one for each 4-byte subblock)
// Bit 24-27: NECRV("Reserved")
// Bit 28-31: 0
typedef enum
{
V810_EMU_MODE_FAST = 0,
V810_EMU_MODE_ACCURATE = 1,
_V810_EMU_MODE_COUNT
} V810_Emu_Mode;
class V810
{
public:
V810() MDFN_COLD;
~V810() MDFN_COLD;
// Pass TRUE for vb_mode if we're emulating a VB-specific enhanced V810 CPU core
bool Init(V810_Emu_Mode mode, bool vb_mode) MDFN_COLD;
void Kill(void) MDFN_COLD;
void SetInt(int level);
void SetMemWriteBus32(uint8 A, bool value) MDFN_COLD;
void SetMemReadBus32(uint8 A, bool value) MDFN_COLD;
void SetMemReadHandlers(uint8 MDFN_FASTCALL (*read8)(v810_timestamp_t &, uint32), uint16 MDFN_FASTCALL (*read16)(v810_timestamp_t &, uint32), uint32 MDFN_FASTCALL (*read32)(v810_timestamp_t &, uint32)) MDFN_COLD;
void SetMemWriteHandlers(void MDFN_FASTCALL (*write8)(v810_timestamp_t &, uint32, uint8), void MDFN_FASTCALL (*write16)(v810_timestamp_t &, uint32, uint16), void MDFN_FASTCALL (*write32)(v810_timestamp_t &, uint32, uint32)) MDFN_COLD;
void SetIOReadHandlers(uint8 MDFN_FASTCALL (*read8)(v810_timestamp_t &, uint32), uint16 MDFN_FASTCALL (*read16)(v810_timestamp_t &, uint32), uint32 MDFN_FASTCALL (*read32)(v810_timestamp_t &, uint32)) MDFN_COLD;
void SetIOWriteHandlers(void MDFN_FASTCALL (*write8)(v810_timestamp_t &, uint32, uint8), void MDFN_FASTCALL (*write16)(v810_timestamp_t &, uint32, uint16), void MDFN_FASTCALL (*write32)(v810_timestamp_t &, uint32, uint32)) MDFN_COLD;
// Length specifies the number of bytes to map in, at each location specified by addresses[] (for mirroring)
uint8 *SetFastMap(uint32 addresses[], uint32 length, unsigned int num_addresses, const char *name, bool writable) MDFN_COLD;
INLINE void ResetTS(v810_timestamp_t new_base_timestamp)
{
assert(next_event_ts > v810_timestamp);
next_event_ts -= (v810_timestamp - new_base_timestamp);
v810_timestamp = new_base_timestamp;
}
INLINE void SetEventNT(const v810_timestamp_t timestamp)
{
next_event_ts = timestamp;
}
INLINE v810_timestamp_t GetEventNT(void)
{
return(next_event_ts);
}
v810_timestamp_t Run(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp));
void Exit(void);
void Reset(void) MDFN_COLD;
#ifdef WANT_DEBUGGER
void CheckBreakpoints(void (*callback)(int type, uint32 address, uint32 value, unsigned int len), uint16 MDFN_FASTCALL (*peek16)(const v810_timestamp_t, uint32), uint32 MDFN_FASTCALL (*peek32)(const v810_timestamp_t, uint32));
void SetCPUHook(void (*newhook)(const v810_timestamp_t timestamp, uint32 PC), void (*new_ADDBT)(uint32, uint32, uint32));
#endif
enum
{
GSREG_PR = 0,
GSREG_SR = 32,
GSREG_PC = 64,
GSREG_TIMESTAMP
};
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
void SetRegister(unsigned int which, uint32 value);
uint32 GetPC(void);
void SetPC(uint32);
INLINE uint32 GetPR(unsigned int which)
{
return which ? P_REG[which] : 0;
}
private:
// Make sure P_REG[] is the first variable/array in this class, so non-zerfo offset encoding(at assembly level) isn't necessary to access it.
uint32 P_REG[32]; // Program registers pr0-pr31
uint32 S_REG[32]; // System registers sr0-sr31
uint32 PC;
uint8 *PC_ptr;
uint8 *PC_base;
uint32 IPendingCache;
void RecalcIPendingCache(void);
public:
v810_timestamp_t v810_timestamp; // Will never be less than 0.
private:
v810_timestamp_t next_event_ts;
enum
{
LASTOP_NORMAL = 0,
LASTOP_LOAD = 1,
LASTOP_STORE = 2,
LASTOP_IN = 3,
LASTOP_OUT = 4,
LASTOP_HEAVY_MATH = 5
};
V810_Emu_Mode EmuMode;
bool VBMode;
void Run_Fast(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp)) NO_INLINE;
void Run_Accurate(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp)) NO_INLINE;
#ifdef WANT_DEBUGGER
void Run_Fast_Debug(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp)) NO_INLINE;
void Run_Accurate_Debug(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp)) NO_INLINE;
#endif
uint8 MDFN_FASTCALL (*MemRead8)(v810_timestamp_t &timestamp, uint32 A);
uint16 MDFN_FASTCALL (*MemRead16)(v810_timestamp_t &timestamp, uint32 A);
uint32 MDFN_FASTCALL (*MemRead32)(v810_timestamp_t &timestamp, uint32 A);
void MDFN_FASTCALL (*MemWrite8)(v810_timestamp_t &timestamp, uint32 A, uint8 V);
void MDFN_FASTCALL (*MemWrite16)(v810_timestamp_t &timestamp, uint32 A, uint16 V);
void MDFN_FASTCALL (*MemWrite32)(v810_timestamp_t &timestamp, uint32 A, uint32 V);
uint8 MDFN_FASTCALL (*IORead8)(v810_timestamp_t &timestamp, uint32 A);
uint16 MDFN_FASTCALL (*IORead16)(v810_timestamp_t &timestamp, uint32 A);
uint32 MDFN_FASTCALL (*IORead32)(v810_timestamp_t &timestamp, uint32 A);
void MDFN_FASTCALL (*IOWrite8)(v810_timestamp_t &timestamp, uint32 A, uint8 V);
void MDFN_FASTCALL (*IOWrite16)(v810_timestamp_t &timestamp, uint32 A, uint16 V);
void MDFN_FASTCALL (*IOWrite32)(v810_timestamp_t &timestamp, uint32 A, uint32 V);
bool MemReadBus32[256]; // Corresponding to the upper 8 bits of the memory address map.
bool MemWriteBus32[256];
int32 lastop; // Set to -1 on FP/MUL/DIV, 0x100 on LD, 0x200 on ST, 0x400 on in, 0x800 on out, and the actual opcode * 2(or >= 0) on everything else.
#define LASTOP_LD 0x100
#define LASTOP_ST 0x200
#define LASTOP_IN 0x400
#define LASTOP_OUT 0x800
enum
{
HALT_NONE = 0,
HALT_HALT = 1,
HALT_FATAL_EXCEPTION = 2
};
uint8 Halted;
bool Running;
int ilevel;
bool in_bstr;
uint16 in_bstr_to;
bool bstr_subop(v810_timestamp_t &timestamp, int sub_op, int arg1);
void fpu_subop(v810_timestamp_t &timestamp, int sub_op, int arg1, int arg2);
void Exception(uint32 handler, uint16 eCode);
// Caching-related:
typedef struct
{
uint32 tag;
uint32 data[2];
bool data_valid[2];
} V810_CacheEntry_t;
V810_CacheEntry_t Cache[128];
// Bitstring variables.
uint32 src_cache;
uint32 dst_cache;
bool have_src_cache, have_dst_cache;
uint8 *FastMap[(1ULL << 32) / V810_FAST_MAP_PSIZE];
#ifdef WANT_DEBUGGER
void (*CPUHook)(const v810_timestamp_t timestamp, uint32 PC);
void (*ADDBT)(uint32 old_PC, uint32 new_PC, uint32);
#endif
// For CacheDump and CacheRestore
void CacheOpMemStore(v810_timestamp_t &timestamp, uint32 A, uint32 V);
uint32 CacheOpMemLoad(v810_timestamp_t &timestamp, uint32 A);
void CacheClear(v810_timestamp_t &timestamp, uint32 start, uint32 count);
void CacheDump(v810_timestamp_t &timestamp, const uint32 SA);
void CacheRestore(v810_timestamp_t &timestamp, const uint32 SA);
uint32 RDCACHE(v810_timestamp_t &timestamp, uint32 addr);
//
// End caching related
//
uint16 RDOP(v810_timestamp_t &timestamp, uint32 addr, uint32 meow = 2);
void SetFlag(uint32 n, bool condition);
void SetSZ(uint32 value);
void SetSREG(v810_timestamp_t &timestamp, unsigned int which, uint32 value);
uint32 GetSREG(unsigned int which);
bool IsSubnormal(uint32 fpval);
void FPU_Math_Template(uint32 (V810_FP_Ops::*func)(uint32, uint32), uint32 arg1, uint32 arg2);
void FPU_DoException(void);
bool CheckFPInputException(uint32 fpval);
bool FPU_DoesExceptionKillResult(void);
void SetFPUOPNonFPUFlags(uint32 result);
uint32 BSTR_RWORD(v810_timestamp_t &timestamp, uint32 A);
void BSTR_WWORD(v810_timestamp_t &timestamp, uint32 A, uint32 V);
bool Do_BSTR_Search(v810_timestamp_t &timestamp, const int inc_mul, unsigned int bit_test);
V810_FP_Ops fpo;
uint8 DummyRegion[V810_FAST_MAP_PSIZE + V810_FAST_MAP_TRAMPOLINE_SIZE];
};
#endif

View File

@ -1,385 +0,0 @@
/* V810 Emulator
*
* Copyright (C) 2006 David Tucker
*
* 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
*/
//////////////////////////////////////////////////////////
// CPU Debug routines
//what do we realy need?
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//#include <ctype.h>
#include "../defs.h"
#include "v810_opt.h"
#include "v810_cpu.h"
#include "v810_cpuD.h"
////////////////////////////////////////////////////////////
// Defines
//Structure to store an element in our linked list
// used to dynamicaly dissasemble a rom
typedef struct dasms {
int offset;
uint32 PC;
uint32 jump;
struct dasms * nextElement;
} dasmS;
typedef struct {
int addr_mode; // Addressing mode
const char * opname; // Opcode name (string)
} operation;
static const operation optable[80] = {
{ AM_I, "mov " }, // 0x00
{ AM_I, "add " }, // 0x01
{ AM_I, "sub " }, // 0x02
{ AM_I, "cmp " }, // 0x03
{ AM_I, "shl " }, // 0x04
{ AM_I, "shr " }, // 0x05
{ AM_I, "jmp " }, // 0x06
{ AM_I, "sar " }, // 0x07
{ AM_I, "mul " }, // 0x08
{ AM_I, "div " }, // 0x09
{ AM_I, "mulu " }, // 0x0A
{ AM_I, "divu " }, // 0x0B
{ AM_I, "or " }, // 0x0C
{ AM_I, "and " }, // 0x0D
{ AM_I, "xor " }, // 0x0E
{ AM_I, "not " }, // 0x0F
{ AM_II, "mov " }, // 0x10 // Imediate
{ AM_II, "add " }, // 0x11
{ AM_II, "setf " }, // 0x12
{ AM_II, "cmp " }, // 0x13
{ AM_II, "shl " }, // 0x14
{ AM_II, "shr " }, // 0x15
{0x8000|AM_IX,"ei " }, // 0x16 // EI(VB only)
{ AM_II, "sar " }, // 0x17
{ AM_II, "trap " }, // 0x18
{ AM_IX, "reti " }, // 0x19 //BRKRETI
{ AM_IX, "halt " }, // 0x1A //STBY
{AM_UDEF, "??? " }, // 0x1B // Unknown
{ AM_II, "ldsr " }, // 0x1C
{ AM_II, "stsr " }, // 0x1D
{0x8000|AM_IX,"di " }, // 0x1E // DI(VB only)
{AM_BSTR, "BSTR " }, // 0x1F // Special Bit String Instructions
{AM_UDEF, "??? " }, // 0x20 // Unknown // This is a fudg on our part
{AM_UDEF, "??? " }, // 0x21 // Unknown // We have 6 and 7 bit instructions
{AM_UDEF, "??? " }, // 0x22 // Unknown // this is filld in by the Conditional Branch Instructions
{AM_UDEF, "??? " }, // 0x23 // Unknown
{AM_UDEF, "??? " }, // 0x24 // Unknown
{AM_UDEF, "??? " }, // 0x25 // Unknown
{AM_UDEF, "??? " }, // 0x26 // Unknown
{AM_UDEF, "??? " }, // 0x27 // Unknown
{ AM_V, "movea" }, // 0x28
{ AM_V, "addi " }, // 0x29
{ AM_IV, "jr " }, // 0x2A
{ AM_IV, "jal " }, // 0x2B
{ AM_V, "ori " }, // 0x2C
{ AM_V, "andi " }, // 0x2D
{ AM_V, "xori " }, // 0x2E
{ AM_V, "movhi" }, // 0x2F
{ AM_VIa, "ld.b " }, // 0x30
{ AM_VIa, "ld.h " }, // 0x31
{AM_UDEF, "??? " }, // 0x32 // Unknown
{ AM_VIa, "ld.w " }, // 0x33
{ AM_VIb, "st.b " }, // 0x34
{ AM_VIb, "st.h " }, // 0x35
{AM_UDEF, "??? " }, // 0x36 // Unknown
{ AM_VIb, "st.w " }, // 0x37
{ AM_VIa, "in.b " }, // 0x38
{ AM_VIa, "in.h " }, // 0x39
{ AM_VIa, "caxi " }, // 0x3A
{ AM_VIa, "in.w " }, // 0x3B
{ AM_VIb, "out.b" }, // 0x3C
{ AM_VIb, "out.h" }, // 0x3D
{ AM_FPP, "FPP " }, // 0x3E //Floating Point Instruction, Special Case
{ AM_VIb, "out.w" }, // 0x3F
{ AM_III, "bv " }, // 0x40
{ AM_III, "bl " }, // 0x41 //BC 0x41
{ AM_III, "be " }, // 0x42 //BZ 0x42
{ AM_III, "bnh " }, // 0x43
{ AM_III, "bn " }, // 0x44
{ AM_III, "br " }, // 0x45
{ AM_III, "blt " }, // 0x46
{ AM_III, "ble " }, // 0x47
{ AM_III, "bnv " }, // 0x48
{ AM_III, "bnl " }, // 0x49 //BNC 0x49
{ AM_III, "bne " }, // 0x4A //BNZ 0x4A
{ AM_III, "bh " }, // 0x4B
{ AM_III, "bp " }, // 0x4C
{ AM_III, "nop " }, // 0x4D
{ AM_III, "bge " }, // 0x4E
{ AM_III, "bgt " } // 0x4F
};
// All instructions greater than 0x50 are undefined (this should not be posible of cource)
//Structure for holding the SubOpcodes, Same as above, without the InsType.
typedef struct {
const char * opname; // Opcode name (string)
} suboperation;
// Bit String Subopcodes
static const suboperation bssuboptable[16] = {
{ "SCH0BSU" }, // 0x00
{ "SCH0BSD" }, // 0x01
{ "SCH1BSU" }, // 0x02
{ "SCH1BSD" }, // 0x03
{ "BError4" }, // 0x04 // Unknown
{ "BError5" }, // 0x05 // Unknown
{ "BError6" }, // 0x06 // Unknown
{ "BError7" }, // 0x07 // Unknown
{ "ORBSU " }, // 0x08
{ "ANDBSU " }, // 0x09
{ "XORBSU " }, // 0x0A
{ "MOVBSU " }, // 0x0B
{ "ORNBSU " }, // 0x0C
{ "ANDNBSU" }, // 0x0D
{ "XORNBSU" }, // 0x0E
{ "NOTBSU " } // 0x0F
};
// Floating Point Subopcodes
static const suboperation fpsuboptable[16] = {
{ "cmpf.s " }, // 0x00
{ "FError1" }, // 0x01 // Unknown
{ "cvt.ws " }, // 0x02
{ "cvt.sw " }, // 0x03
{ "addf.s " }, // 0x04
{ "subf.s " }, // 0x05
{ "mulf.s " }, // 0x06
{ "divf.s " }, // 0x07
{ "FError8" }, // 0x08 // Invalid
{ "FError9" }, // 0x09 // Invalid
{ "FErrorA" }, // 0x0A // Invalid
{ "FErrorB" }, // 0x0B // Invalid
{ "FErrorC" }, // 0x0C // Invalid
{ "FErrorD" }, // 0x0D // Invalid
{ "FErrorE" }, // 0x0E // Invalid
{ "FErrorF" } // 0x0F // Invalid
};
static const suboperation fpsuboptable_vb[16] = {
{ "cmpf.s " }, // 0x00
{ "FError1" }, // 0x01 // Unknown
{ "cvt.ws " }, // 0x02
{ "cvt.sw " }, // 0x03
{ "addf.s " }, // 0x04
{ "subf.s " }, // 0x05
{ "mulf.s " }, // 0x06
{ "divf.s " }, // 0x07
{ "XB" }, // 0x08 // undocumented
{ "XH" }, // 0x09 // undocumented //VFishing???
{ "REV" }, // 0x0A // undocumented
{ "trnc.sw" }, // 0x0B
{ "MPYHW" }, // 0x0C // undocumented
{ "FErrorD" }, // 0x0D // Unknown
{ "FErrorE" }, // 0x0E // Unknown
{ "FErrorF" } // 0x0F // Unknown
};
static const char *pretty_preg_names[32] =
{
"r0", "r1", "hsp", "sp", "gp", "tp", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "lp",
};
static const char *pretty_sreg_names[32] =
{
"sr0(eipc)", "sr1(eipsw)", "sr2(fepc)", "sr3(fepsw)", "sr4(ecr)", "sr5(psw)", "sr6(pir)", "sr7(tkcw)",
"sr8(invalid)", "sr9(invalid)", "sr10(invalid)", "sr11(invalid)", "sr12(invalid)", "sr13(invalid)",
"sr14(invalid)", "sr15(invalid)", "sr16(invalid)", "sr17(invalid)", "sr18(invalid)", "sr19(invalid)",
"sr20(invalid)", "sr21(invalid)", "sr22(invalid)", "sr23(invalid)",
"sr24(chcw)", "sr25(adtre)", "sr26(invalid)", "sr27(invalid)", "sr28(invalid)", "sr29(invalid)", "sr30(invalid)",
"sr31(invalid)"
};
void v810_dis(uint32 &tPC, int num, char *buf, uint16 (*rhword)(uint32), bool vbmode)
{
int lowB, highB, lowB2, highB2; // up to 4 bytes for instruction (either 16 or 32 bits)
int opcode, arg1, arg2, arg3;
int i = 0;
buf[0] = 0;
for(i = 0; i< num; i++)
{
const uint16 hw0 = rhword(tPC);
const uint16 hw1 = rhword(tPC + 2);
lowB = hw0 & 0xFF;
highB = hw0 >> 8;
lowB2 = hw1 & 0xFF;
highB2 = hw1 >> 8;
opcode = highB >> 2;
if((highB & 0xE0) == 0x80) // Special opcode format for
opcode = (highB >> 1); // type III instructions.
if((opcode > 0x4F) | (opcode < 0)) {
//Error Invalid opcode!
sprintf(&buf[strlen(buf)], "0x%04x", hw0);
tPC += 2;
}
int am = optable[opcode].addr_mode;
if((am & 0x8000) && !vbmode)
am = AM_UDEF;
am &= ~0x8000;
switch(am) {
case AM_I: // Do the same Ither way =)
arg1 = (lowB >> 5) + ((highB & 0x3) << 3);
arg2 = (lowB & 0x1F);
if (opcode == JMP) {
sprintf(&buf[strlen(buf)],"%s [%s]", optable[opcode].opname, pretty_preg_names[arg2]);
} else {
sprintf(&buf[strlen(buf)],"%s %s, %s", optable[opcode].opname, pretty_preg_names[arg2], pretty_preg_names[arg1]);
}
tPC += 2; // 16 bit instruction
break;
case AM_II:
arg1 = (lowB >> 5) + ((highB & 0x3) << 3);
arg2 = (lowB & 0x1F);
if(opcode == LDSR) {
sprintf(&buf[strlen(buf)],"%s %s, %s", optable[opcode].opname, pretty_preg_names[arg1], pretty_sreg_names[arg2]);
} else if(opcode == STSR) {
sprintf(&buf[strlen(buf)],"%s %s, %s", optable[opcode].opname, pretty_sreg_names[arg2], pretty_preg_names[arg1]);
} else if(opcode == ADD_I || opcode == CMP_I || opcode == MOV_I) {
sprintf(&buf[strlen(buf)],"%s %d, %s", optable[opcode].opname, sign_5(arg2), pretty_preg_names[arg1]);
} else {
sprintf(&buf[strlen(buf)],"%s %d, %s", optable[opcode].opname, arg2, pretty_preg_names[arg1]);
}
tPC += 2; // 16 bit instruction
break;
case AM_III:
arg1 = ((highB & 0x1) << 8) + (lowB & 0xFE);
if(opcode == NOP)
sprintf(&buf[strlen(buf)],"%s", optable[opcode].opname);
else
sprintf(&buf[strlen(buf)],"%s %08x", optable[opcode].opname, tPC + sign_9(arg1));
tPC += 2; // 16 bit instruction
break;
case AM_IV:
arg1 = ((highB & 0x3) << 24) + (lowB << 16) + (highB2 << 8) + lowB2;
sprintf(&buf[strlen(buf)],"%s %08x", optable[opcode].opname, tPC + sign_26(arg1));
tPC += 4; // 32 bit instruction
break;
case AM_V:
arg1 = (lowB >> 5) + ((highB & 0x3) << 3);
arg2 = (lowB & 0x1F);
arg3 = (highB2 << 8) + lowB2;
// TODO: What would be the best way to disassemble the MOVEA instruction?
//if(opcode == MOVEA)
// sprintf(&buf[strlen(buf)],"%s 0x%X, %s, %s", optable[opcode].opname, (uint32)(int32)(int16)(uint16)arg3, pretty_preg_names[arg2], pretty_preg_names[arg1] );
//else
sprintf(&buf[strlen(buf)],"%s 0x%X, %s, %s", optable[opcode].opname, arg3, pretty_preg_names[arg2], pretty_preg_names[arg1] );
tPC += 4; // 32 bit instruction
break;
case AM_VIa: // Mode6 form1
arg1 = (lowB >> 5) + ((highB & 0x3) << 3);
arg2 = (lowB & 0x1F);
arg3 = (highB2 << 8) + lowB2;
if(!arg3) // Don't bother printing offset if it's 0
sprintf(&buf[strlen(buf)],"%s [%s], %s", optable[opcode].opname, pretty_preg_names[arg2], pretty_preg_names[arg1]);
else if(sign_16(arg3) >= 0) // Make disassembly prettier if it's a positive offset
sprintf(&buf[strlen(buf)],"%s 0x%04x[%s], %s", optable[opcode].opname, sign_16(arg3), pretty_preg_names[arg2], pretty_preg_names[arg1]);
else
sprintf(&buf[strlen(buf)],"%s %d[%s], %s", optable[opcode].opname, sign_16(arg3), pretty_preg_names[arg2], pretty_preg_names[arg1]);
tPC += 4; // 32 bit instruction
break;
case AM_VIb: // Mode6 form2
arg1 = (lowB >> 5) + ((highB & 0x3) << 3);
arg2 = (lowB & 0x1F);
arg3 = (highB2 << 8) + lowB2; // whats the order??? 2,3,1 or 1,3,2
if(!arg3) // Don't bother printing offset if it's 0
sprintf(&buf[strlen(buf)],"%s %s, [%s]", optable[opcode].opname, pretty_preg_names[arg1], pretty_preg_names[arg2]);
else if(sign_16(arg3) >= 0) // Make disassembly prettier if it's a positive offset
sprintf(&buf[strlen(buf)],"%s %s, 0x%04x[%s]", optable[opcode].opname, pretty_preg_names[arg1], sign_16(arg3), pretty_preg_names[arg2]);
else
sprintf(&buf[strlen(buf)],"%s %s, %d[%s]", optable[opcode].opname, pretty_preg_names[arg1], sign_16(arg3), pretty_preg_names[arg2]);
tPC += 4; // 32 bit instruction
break;
case AM_VII: // Unhandled
sprintf(&buf[strlen(buf)],"0x%2x 0x%2x 0x%2x 0x%2x", lowB, highB, lowB2, highB2);
tPC +=4; // 32 bit instruction
break;
case AM_VIII: // Unhandled
sprintf(&buf[strlen(buf)],"0x%2x 0x%2x 0x%2x 0x%2x", lowB, highB, lowB2, highB2);
tPC += 4; // 32 bit instruction
break;
case AM_IX:
arg1 = (lowB & 0x1); // Mode ID, Ignore for now
sprintf(&buf[strlen(buf)],"%s", optable[opcode].opname);
tPC += 2; // 16 bit instruction
break;
case AM_BSTR: // Bit String Subopcodes
arg1 = (lowB >> 5) + ((highB & 0x3) << 3);
arg2 = (lowB & 0x1F);
if(arg2 > 15) {
sprintf(&buf[strlen(buf)],"BError");
} else {
//sprintf(&buf[strlen(buf)],"%s, $%d", bssuboptable[arg2].opname,arg1);
sprintf(&buf[strlen(buf)], "%s", bssuboptable[arg2].opname);
}
tPC += 2; // 16 bit instruction
break;
case AM_FPP: // Floating Point Subcode
arg1 = (lowB >> 5) + ((highB & 0x3) << 3);
arg2 = (lowB & 0x1F);
arg3 = (highB2 >> 2);
if(arg3 > 15) {
sprintf(&buf[strlen(buf)],"(Invalid FPU: 0x%02x)", arg3);
} else {
sprintf(&buf[strlen(buf)],"%s %s, %s", (vbmode ? fpsuboptable_vb[arg3].opname : fpsuboptable[arg3].opname), pretty_preg_names[arg2], pretty_preg_names[arg1]);
}
tPC += 4; // 32 bit instruction
break;
case AM_UDEF: // Invalid opcode.
default: // Invalid opcode.
sprintf(&buf[strlen(buf)],"0x%04x", hw0);
tPC += 2;
}
}
}

View File

@ -1,15 +0,0 @@
////////////////////////////////////////////////////////////////
// Defines for the V810 CPU debug
#ifndef V810_CPU_D_H_
#define V810_CPU_D_H_
#include <stdio.h>
#include <string>
#include "v810_opt.h"
// Dissasemble num lines of code starting at tPC (If tPC == -1 start at PC)
void v810_dis(uint32 &PC, int num, char *, uint16 (*rhword)(uint32), bool vbmode = false);
#endif

View File

@ -1,72 +0,0 @@
#define DO_MOV_AM(); DO_AM_I();
#define DO_ADD_AM(); DO_AM_I();
#define DO_SUB_AM(); DO_AM_I();
#define DO_CMP_AM(); DO_AM_I();
#define DO_SHL_AM(); DO_AM_I();
#define DO_SHR_AM(); DO_AM_I();
#define DO_JMP_AM(); DO_AM_I();
#define DO_SAR_AM(); DO_AM_I();
#define DO_MUL_AM(); DO_AM_I();
#define DO_DIV_AM(); DO_AM_I();
#define DO_MULU_AM(); DO_AM_I();
#define DO_DIVU_AM(); DO_AM_I();
#define DO_OR_AM(); DO_AM_I();
#define DO_AND_AM(); DO_AM_I();
#define DO_XOR_AM(); DO_AM_I();
#define DO_NOT_AM(); DO_AM_I();
#define DO_MOV_I_AM(); DO_AM_II();
#define DO_ADD_I_AM(); DO_AM_II();
#define DO_SETF_AM(); DO_AM_II();
#define DO_CMP_I_AM(); DO_AM_II();
#define DO_SHL_I_AM(); DO_AM_II();
#define DO_SHR_I_AM(); DO_AM_II();
#define DO_EI_AM(); DO_AM_II();
#define DO_SAR_I_AM(); DO_AM_II();
#define DO_TRAP_AM(); DO_AM_II();
#define DO_RETI_AM(); DO_AM_IX();
#define DO_HALT_AM(); DO_AM_IX();
#define DO_LDSR_AM(); DO_AM_II();
#define DO_STSR_AM(); DO_AM_II();
#define DO_DI_AM(); DO_AM_II();
#define DO_BSTR_AM(); DO_AM_BSTR();
#define DO_MOVEA_AM(); DO_AM_V();
#define DO_ADDI_AM(); DO_AM_V();
#define DO_JR_AM(); DO_AM_IV();
#define DO_JAL_AM(); DO_AM_IV();
#define DO_ORI_AM(); DO_AM_V();
#define DO_ANDI_AM(); DO_AM_V();
#define DO_XORI_AM(); DO_AM_V();
#define DO_MOVHI_AM(); DO_AM_V();
#define DO_LD_B_AM(); DO_AM_VIa();
#define DO_LD_H_AM(); DO_AM_VIa();
#define DO_LD_W_AM(); DO_AM_VIa();
#define DO_ST_B_AM(); DO_AM_VIb();
#define DO_ST_H_AM(); DO_AM_VIb();
#define DO_ST_W_AM(); DO_AM_VIb();
#define DO_IN_B_AM(); DO_AM_VIa();
#define DO_IN_H_AM(); DO_AM_VIa();
#define DO_CAXI_AM(); DO_AM_VIa();
#define DO_IN_W_AM(); DO_AM_VIa();
#define DO_OUT_B_AM(); DO_AM_VIb();
#define DO_OUT_H_AM(); DO_AM_VIb();
#define DO_FPP_AM(); DO_AM_FPP();
#define DO_OUT_W_AM(); DO_AM_VIb();
#define DO_BV_AM(); DO_AM_III();
#define DO_BL_AM(); DO_AM_III();
#define DO_BE_AM(); DO_AM_III();
#define DO_BNH_AM(); DO_AM_III();
#define DO_BN_AM(); DO_AM_III();
#define DO_BR_AM(); DO_AM_III();
#define DO_BLT_AM(); DO_AM_III();
#define DO_BLE_AM(); DO_AM_III();
#define DO_BNV_AM(); DO_AM_III();
#define DO_BNL_AM(); DO_AM_III();
#define DO_BNE_AM(); DO_AM_III();
#define DO_BH_AM(); DO_AM_III();
#define DO_BP_AM(); DO_AM_III();
#define DO_NOP_AM(); DO_AM_III();
#define DO_BGE_AM(); DO_AM_III();
#define DO_BGT_AM(); DO_AM_III();
#define DO_INVALID_AM(); DO_AM_UDEF();

View File

@ -1,408 +0,0 @@
/******************************************************************************/
/* Mednafen - Multi-system Emulator */
/******************************************************************************/
/* v810_fp_ops.cpp:
** Copyright (C) 2014-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "v810_fp_ops.h"
bool V810_FP_Ops::fp_is_zero(uint32 v)
{
return((v & 0x7FFFFFFF) == 0);
}
#if 0
bool V810_FP_Ops::fp_is_nan(uint32 v)
{
return((v & 0x7FFFFFFF) > (255 << 23));
}
bool V810_FP_Ops::fp_is_inf(uint32 v)
{
return((v & 0x7FFFFFFF) == (255 << 23));
}
#endif
bool V810_FP_Ops::fp_is_inf_nan_sub(uint32 v)
{
if((v & 0x7FFFFFFF) == 0)
return(false);
switch((v >> 23) & 0xFF)
{
case 0x00:
case 0xff:
return(true);
}
return(false);
}
void V810_FP_Ops::fpim_decode(fpim* df, uint32 v)
{
df->exp = ((v >> 23) & 0xFF) - 127;
df->f = (v & 0x7FFFFF) | ((v & 0x7FFFFFFF) ? 0x800000 : 0);
df->sign = v >> 31;
}
void V810_FP_Ops::fpim_round(fpim* df)
{
int vbc = 64 - MDFN_lzcount64(df->f);
if(vbc > 24)
{
const unsigned sa = vbc - 24;
if(1) // round to nearest
{
uint64 old_f = df->f;
df->f = (df->f + ((df->f >> sa) & 1) + ((1ULL << (sa - 1)) - 1)) & ~((1ULL << sa) - 1);
if(df->f != old_f)
{
//printf("Inexact mr\n");
exception_flags |= flag_inexact;
}
}
else
abort();
}
}
void V810_FP_Ops::fpim_round_int(fpim* df, bool truncate)
{
if(df->exp < 23)
{
const unsigned sa = 23 - df->exp;
uint64 old_f = df->f;
//if(sa >= 2)
// printf("RI: %lld, %d\n", df->f, sa);
// round to nearest
if(sa > 24)
df->f = 0;
else
{
if(truncate)
df->f = df->f & ~((1ULL << sa) - 1);
else
df->f = (df->f + ((df->f >> sa) & 1) + ((1ULL << (sa - 1)) - 1)) & ~((1ULL << sa) - 1);
}
if(df->f != old_f)
{
//printf("Inexact\n");
exception_flags |= flag_inexact;
}
}
}
uint32 V810_FP_Ops::fpim_encode(fpim* df)
{
const int lzc = MDFN_lzcount64(df->f);
int tmp_exp = df->exp - lzc;
uint64 tmp_walrus = df->f << (lzc & 0x3F);
int tmp_sign = df->sign;
tmp_exp += 40;
tmp_walrus >>= 40;
if(tmp_walrus == 0)
tmp_exp = -127;
else if(tmp_exp <= -127)
{
exception_flags |= flag_underflow | flag_inexact;
//printf("Subnormal: %lld. %d\n", tmp_walrus, tmp_exp);
if(1)
{
tmp_exp = -127;
tmp_walrus = 0;
}
else
{
tmp_walrus >>= -(tmp_exp + 126);
tmp_exp = -127;
}
}
else if(tmp_exp >= 128)
{
exception_flags |= flag_overflow;
//printf("Overflow!\n");
if(1)
tmp_exp -= 192;
else
{
tmp_exp = 128;
tmp_walrus = 0;
}
}
return (tmp_sign << 31) | ((tmp_exp + 127) << 23) | (tmp_walrus & 0x7FFFFF);
}
uint32 V810_FP_Ops::mul(uint32 a, uint32 b)
{
fpim ins[2];
fpim res;
if(fp_is_inf_nan_sub(a) || fp_is_inf_nan_sub(b))
{
exception_flags |= flag_reserved;
return(~0U);
}
fpim_decode(&ins[0], a);
fpim_decode(&ins[1], b);
//printf("%08x %08x - %d %d %d - %d %d %d\n", a, b, a_exp, a_walrus, a_sign, b_exp, b_walrus, b_sign);
res.exp = ins[0].exp + ins[1].exp - 23;
res.f = ins[0].f * ins[1].f;
res.sign = ins[0].sign ^ ins[1].sign;
fpim_round(&res);
return fpim_encode(&res);
}
uint32 V810_FP_Ops::add(uint32 a, uint32 b)
{
fpim ins[2];
fpim res;
int64 ft[2];
int64 tr;
int max_exp;
if(fp_is_inf_nan_sub(a) || fp_is_inf_nan_sub(b))
{
exception_flags |= flag_reserved;
return(~0U);
}
if(a == b && !(a & 0x7FFFFFFF))
{
return(a & 0x80000000);
}
fpim_decode(&ins[0], a);
fpim_decode(&ins[1], b);
max_exp = std::max<int>(ins[0].exp, ins[1].exp);
//printf("%d:%08llx %d:%08llx\n", ins[0].exp, ins[0].f, ins[1].exp, ins[1].f);
for(unsigned i = 0; i < 2; i++)
{
unsigned sd = (max_exp - ins[i].exp);
ft[i] = ins[i].f << 24;
if(sd >= 48)
{
if(ft[i] != 0)
ft[i] = 1;
}
else
{
int64 nft = ft[i] >> sd;
if(ft[i] != (nft << sd))
{
nft |= 1;
}
//{
// puts("FPR");
// }
ft[i] = nft;
}
if(ins[i].sign)
ft[i] = -ft[i];
}
//printf("SOON: %08llx %08llx\n", ft[0], ft[1]);
tr = ft[0] + ft[1];
if(tr < 0)
{
tr = -tr;
res.sign = true;
}
else
res.sign = false;
res.f = tr;
res.exp = max_exp - 24;
fpim_round(&res);
return fpim_encode(&res);
}
uint32 V810_FP_Ops::sub(uint32 a, uint32 b)
{
return add(a, b ^ 0x80000000);
}
uint32 V810_FP_Ops::div(uint32 a, uint32 b)
{
fpim ins[2];
fpim res;
uint64 mtmp;
if(fp_is_inf_nan_sub(a) || fp_is_inf_nan_sub(b))
{
exception_flags |= flag_reserved;
return(~0U);
}
if(fp_is_zero(a) && fp_is_zero(b))
{
exception_flags |= flag_invalid;
return(~0U);
}
fpim_decode(&ins[0], a);
fpim_decode(&ins[1], b);
res.sign = ins[0].sign ^ ins[1].sign;
if(ins[1].f == 0)
{
//puts("Divide by zero!");
exception_flags |= flag_divbyzero;
return((res.sign << 31) | (255 << 23));
}
else
{
res.exp = ins[0].exp - ins[1].exp - 2 - 1; // + 23 - 2;
res.f = ((ins[0].f << 24) / ins[1].f) << 2;
mtmp = ((ins[0].f << 24) % ins[1].f) << 1;
//printf("%lld %lld\n", (ins[0].f << 23) % ins[1].f, ins[1].f);
if(mtmp > ins[1].f)
res.f |= 3;
else if(mtmp == ins[1].f)
res.f |= 2;
else if(mtmp > 0)
res.f |= 1;
}
fpim_round(&res);
return fpim_encode(&res);
}
int V810_FP_Ops::cmp(uint32 a, uint32 b)
{
fpim ins[2];
if(fp_is_inf_nan_sub(a) || fp_is_inf_nan_sub(b))
{
exception_flags |= flag_reserved;
return(~0U);
}
fpim_decode(&ins[0], a);
fpim_decode(&ins[1], b);
if(ins[0].exp > ins[1].exp)
return(ins[0].sign ? -1 : 1);
if(ins[0].exp < ins[1].exp)
return(ins[1].sign ? 1 : -1);
if(ins[0].f > ins[1].f)
return(ins[0].sign ? -1 : 1);
if(ins[0].f < ins[1].f)
return(ins[1].sign ? 1 : -1);
if((ins[0].sign ^ ins[1].sign) && ins[0].f != 0)
return(ins[0].sign ? -1 : 1);
return(0);
}
uint32 V810_FP_Ops::itof(uint32 v)
{
fpim res;
res.sign = (bool)(v & 0x80000000);
res.exp = 23;
res.f = res.sign ? (0x80000000 - (v & 0x7FFFFFFF)) : (v & 0x7FFFFFFF);
fpim_round(&res);
return fpim_encode(&res);
}
uint32 V810_FP_Ops::ftoi(uint32 v, bool truncate)
{
fpim ins;
int sa;
int ret;
if(fp_is_inf_nan_sub(v))
{
exception_flags |= flag_reserved;
return(~0U);
}
fpim_decode(&ins, v);
fpim_round_int(&ins, truncate);
sa = ins.exp - 23;
if(sa < 0)
{
if(sa <= -32)
ret = 0;
else
ret = ins.f >> -sa;
}
else
{
if(sa >= 8)
{
if(sa == 8 && ins.f == 0x800000 && ins.sign)
return(0x80000000);
else
{
ret = ~0U;
exception_flags |= flag_invalid;
}
}
else
{
ret = ins.f << sa;
}
}
//printf("%d\n", sa);
if(ins.sign)
ret = -ret;
return(ret);
}

View File

@ -1,77 +0,0 @@
/******************************************************************************/
/* Mednafen - Multi-system Emulator */
/******************************************************************************/
/* v810_fp_ops.h:
** Copyright (C) 2014-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "../defs.h"
class V810_FP_Ops
{
public:
uint32 mul(uint32 a, uint32 b);
uint32 div(uint32 a, uint32 b);
uint32 add(uint32 a, uint32 b);
uint32 sub(uint32 a, uint32 b);
int cmp(uint32 a, uint32 b);
uint32 itof(uint32 v);
uint32 ftoi(uint32 v, bool truncate);
enum
{
flag_invalid = 0x0001,
flag_divbyzero = 0x0002,
flag_overflow = 0x0004,
flag_underflow = 0x0008,
flag_inexact = 0x0010,
flag_reserved = 0x0020
};
inline uint32 get_flags(void)
{
return exception_flags;
}
inline void clear_flags(void)
{
exception_flags = 0;
}
private:
unsigned exception_flags;
struct fpim
{
uint64 f;
int exp;
bool sign;
};
bool fp_is_zero(uint32 v);
bool fp_is_inf_nan_sub(uint32 v);
unsigned clz64(uint64 v);
void fpim_decode(fpim* df, uint32 v);
void fpim_round(fpim* df);
void fpim_round_int(fpim* df, bool truncate = false);
uint32 fpim_encode(fpim* df);
};

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +0,0 @@
///////////////////////////////////////////////////////////////
// File: v810_opt.h
//
// Description: Defines used in v810_dis.cpp
//
#ifndef V810_OPT_H_
#define V810_OPT_H_
#define sign_26(num) ((uint32)sign_x_to_s32(26, num))
#define sign_16(num) ((uint32)(int16)(num))
#define sign_14(num) ((uint32)sign_x_to_s32(14, num))
#define sign_12(num) ((uint32)sign_x_to_s32(12, num))
#define sign_9(num) ((uint32)sign_x_to_s32(9, num))
#define sign_8(_value) ((uint32)(int8)(_value))
#define sign_5(num) ((uint32)sign_x_to_s32(5, num))
///////////////////////////////////////////////////////////////////
// Define Modes
#define AM_I 0x01
#define AM_II 0x02
#define AM_III 0x03
#define AM_IV 0x04
#define AM_V 0x05
#define AM_VIa 0x06 // Mode6 form1
#define AM_VIb 0x0A // Mode6 form2
#define AM_VII 0x07
#define AM_VIII 0x08
#define AM_IX 0x09
#define AM_BSTR 0x0B // Bit String Instructions
#define AM_FPP 0x0C // Floating Point Instructions
#define AM_UDEF 0x0D // Unknown/Undefined Instructions
///////////////////////////////////////////////////////////////////
// Table of Instructions Address Modes
static const int addr_mode[80] = {
AM_I, AM_I, AM_I, AM_I, AM_I, AM_I, AM_I, AM_I,
AM_I, AM_I, AM_I, AM_I, AM_I, AM_I, AM_I, AM_I,
AM_II, AM_II, AM_II, AM_II, AM_II, AM_II, AM_II, AM_II,
AM_II, AM_IX, AM_IX, AM_UDEF, AM_II, AM_II, AM_II, AM_BSTR,
AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF,
AM_V, AM_V, AM_IV, AM_IV, AM_V, AM_V, AM_V, AM_V,
AM_VIa, AM_VIa, AM_UDEF, AM_VIa, AM_VIb, AM_VIb, AM_UDEF, AM_VIb,
AM_VIa, AM_VIa, AM_VIa, AM_VIa, AM_VIb, AM_VIb, AM_FPP, AM_VIb,
AM_III, AM_III, AM_III, AM_III, AM_III, AM_III, AM_III, AM_III,
AM_III, AM_III, AM_III, AM_III, AM_III, AM_III, AM_III, AM_III
};
// All instructions greater than 0x50 are undefined (this should not be posible of cource)
///////////////////////////////////////////////////////////////////
// Opcodes for V810 Instruction set
#define MOV 0x00
#define ADD 0x01
#define SUB 0x02
#define CMP 0x03
#define SHL 0x04
#define SHR 0x05
#define JMP 0x06
#define SAR 0x07
#define MUL 0x08
#define DIV 0x09
#define MULU 0x0A
#define DIVU 0x0B
#define OR 0x0C
#define AND 0x0D
#define XOR 0x0E
#define NOT 0x0F
#define MOV_I 0x10
#define ADD_I 0x11
#define SETF 0x12
#define CMP_I 0x13
#define SHL_I 0x14
#define SHR_I 0x15
#define EI 0x16
#define SAR_I 0x17
#define TRAP 0x18
#define RETI 0x19
#define HALT 0x1A
//0x1B
#define LDSR 0x1C
#define STSR 0x1D
#define DI 0x1E
#define BSTR 0x1F //Special Bit String Inst
//0x20 - 0x27 // Lost to Branch Instructions
#define MOVEA 0x28
#define ADDI 0x29
#define JR 0x2A
#define JAL 0x2B
#define ORI 0x2C
#define ANDI 0x2D
#define XORI 0x2E
#define MOVHI 0x2F
#define LD_B 0x30
#define LD_H 0x31
//0x32
#define LD_W 0x33
#define ST_B 0x34
#define ST_H 0x35
//0x36
#define ST_W 0x37
#define IN_B 0x38
#define IN_H 0x39
#define CAXI 0x3A
#define IN_W 0x3B
#define OUT_B 0x3C
#define OUT_H 0x3D
#define FPP 0x3E //Special Float Inst
#define OUT_W 0x3F
// Branch Instructions ( Extended opcode only for Branch command)
// Common instrcutions commented out
#define BV 0x40
#define BL 0x41
#define BE 0x42
#define BNH 0x43
#define BN 0x44
#define BR 0x45
#define BLT 0x46
#define BLE 0x47
#define BNV 0x48
#define BNL 0x49
#define BNE 0x4A
#define BH 0x4B
#define BP 0x4C
#define NOP 0x4D
#define BGE 0x4E
#define BGT 0x4F
//#define BC 0x41
//#define BZ 0x42
//#define BNC 0x49
//#define BNZ 0x4A
// Bit String Subopcodes
#define SCH0BSU 0x00
#define SCH0BSD 0x01
#define SCH1BSU 0x02
#define SCH1BSD 0x03
#define ORBSU 0x08
#define ANDBSU 0x09
#define XORBSU 0x0A
#define MOVBSU 0x0B
#define ORNBSU 0x0C
#define ANDNBSU 0x0D
#define XORNBSU 0x0E
#define NOTBSU 0x0F
// Floating Point Subopcodes
#define CMPF_S 0x00
#define CVT_WS 0x02
#define CVT_SW 0x03
#define ADDF_S 0x04
#define SUBF_S 0x05
#define MULF_S 0x06
#define DIVF_S 0x07
#define XB 0x08
#define XH 0x09
#define REV 0x0A
#define TRNC_SW 0x0B
#define MPYHW 0x0C
#endif //DEFINE_H

View File

@ -1,51 +0,0 @@
{
"files.associations": {
"iosfwd": "cpp",
"xstring": "cpp",
"xutility": "cpp",
"system_error": "cpp",
"xlocale": "cpp",
"*.inc": "cpp",
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"bitset": "cpp",
"cmath": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"cwchar": "cpp",
"deque": "cpp",
"exception": "cpp",
"initializer_list": "cpp",
"ios": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"memory": "cpp",
"new": "cpp",
"ostream": "cpp",
"queue": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"utility": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xiosbase": "cpp",
"xlocinfo": "cpp",
"xlocnum": "cpp",
"xmemory": "cpp",
"xmemory0": "cpp",
"xstddef": "cpp",
"xtr1common": "cpp"
},
"editor.insertSpaces": false,
"editor.tabSize": 4,
"editor.detectIndentation": false
}

View File

@ -1,10 +0,0 @@
CXXFLAGS := \
-Wall -Werror=int-to-pointer-cast \
-std=c++0x -fomit-frame-pointer -fno-exceptions -fno-rtti \
-DLSB_FIRST
TARGET = ss.wbx
SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
include ../common.mak

View File

@ -1,328 +0,0 @@
#include "ss.h"
#include <memory>
#include "cdrom/cdromif.h"
#include "cdb.h"
#include "smpc.h"
#include "cart.h"
#include <ctime>
#define EXPORT extern "C" ECL_EXPORT
using namespace MDFN_IEN_SS;
int32 (*FirmwareSizeCallback)(const char *filename);
void (*FirmwareDataCallback)(const char *filename, uint8 *dest);
EXPORT void SetFirmwareCallbacks(int32 (*sizecallback)(const char *filename), void (*datacallback)(const char *filename, uint8 *dest))
{
FirmwareSizeCallback = sizecallback;
FirmwareDataCallback = datacallback;
}
struct FrontendTOC
{
int32 FirstTrack;
int32 LastTrack;
int32 DiskType;
struct
{
int32 Adr;
int32 Control;
int32 Lba;
int32 Valid;
} Tracks[101];
};
static void (*ReadTOCCallback)(int disk, FrontendTOC *dest);
static void (*ReadSector2448Callback)(int disk, int lba, uint8 *dest);
EXPORT void SetCDCallbacks(void (*toccallback)(int disk, FrontendTOC *dest), void (*sectorcallback)(int disk, int lba, uint8 *dest))
{
ReadTOCCallback = toccallback;
ReadSector2448Callback = sectorcallback;
}
class MyCDIF : public CDIF
{
private:
int disk;
public:
MyCDIF(int disk) : disk(disk)
{
FrontendTOC t;
ReadTOCCallback(disk, &t);
disc_toc.first_track = t.FirstTrack;
disc_toc.last_track = t.LastTrack;
disc_toc.disc_type = t.DiskType;
for (int i = 0; i < 101; i++)
{
disc_toc.tracks[i].adr = t.Tracks[i].Adr;
disc_toc.tracks[i].control = t.Tracks[i].Control;
disc_toc.tracks[i].lba = t.Tracks[i].Lba;
disc_toc.tracks[i].valid = t.Tracks[i].Valid;
}
}
virtual void HintReadSector(int32 lba) {}
virtual bool ReadRawSector(uint8 *buf, int32 lba)
{
ReadSector2448Callback(disk, lba, buf);
return true;
}
virtual bool ReadRawSectorPWOnly(uint8 *pwbuf, int32 lba, bool hint_fullread)
{
uint8 buff[2448];
ReadSector2448Callback(disk, lba, buff);
memcpy(pwbuf, buff + 2352, 96);
return true;
}
};
static std::vector<CDIF *> CDInterfaces;
static uint32 *FrameBuffer;
static uint8 IsResetPushed; // 1 or 0
namespace MDFN_IEN_SS
{
extern bool LoadCD(std::vector<CDIF *> *CDInterfaces);
}
EXPORT bool Init(int numDisks, int cartType, int regionDefault, int regionAutodetect)
{
setting_ss_cart = cartType;
setting_ss_region_autodetect = regionAutodetect;
setting_ss_region_default = regionDefault;
FrameBuffer = (uint32 *)alloc_invisible(1024 * 1024 * sizeof(*FrameBuffer));
for (int i = 0; i < numDisks; i++)
CDInterfaces.push_back(new MyCDIF(i));
auto ret = LoadCD(&CDInterfaces);
if (ret)
SMPC_SetInput(12, nullptr, &IsResetPushed);
return ret;
}
EXPORT void HardReset()
{
// soft reset is handled as a normal button
SS_Reset(true);
}
EXPORT void SetDisk(int disk, bool open)
{
CDB_SetDisc(open, disk < 0 ? nullptr : CDInterfaces[disk]);
}
int setting_ss_slstartp = 0;
int setting_ss_slendp = 255;
int setting_ss_slstart = 0;
int setting_ss_slend = 239;
int setting_ss_region_default = SMPC_AREA_JP;
int setting_ss_cart = CART_NONE;
bool setting_ss_correct_aspect = true;
bool setting_ss_h_blend = false;
bool setting_ss_h_overscan = true;
bool setting_ss_region_autodetect = true;
bool setting_ss_input_sport1_multitap = false;
bool setting_ss_input_sport0_multitap = false;
namespace MDFN_IEN_SS
{
extern void Emulate(EmulateSpecStruct *espec_arg);
}
static uint8 ControllerInput[12 * 32];
bool InputLagged;
EXPORT void SetControllerData(const uint8_t* controllerData)
{
memcpy(ControllerInput, controllerData, sizeof(ControllerInput));
}
struct MyFrameInfo: public FrameInfo
{
int32_t ResetPushed;
};
EXPORT void FrameAdvance(MyFrameInfo& f)
{
EmulateSpecStruct e;
int32 LineWidths[1024];
memset(LineWidths, 0, sizeof(LineWidths));
e.pixels = FrameBuffer;
e.pitch32 = 1024;
e.LineWidths = LineWidths;
e.SoundBuf = f.SoundBuffer;
e.SoundBufMaxSize = 8192;
IsResetPushed = f.ResetPushed;
InputLagged = true;
Emulate(&e);
f.Samples = e.SoundBufSize;
f.Cycles = e.MasterCycles;
f.Lagged = InputLagged;
int w = 256;
for (int i = 0; i < e.h; i++)
w = std::max(w, LineWidths[i]);
const uint32 *src = FrameBuffer;
uint32 *dst = f.VideoBuffer;
const int srcp = 1024;
const int dstp = w;
src += e.y * srcp + e.x;
for (int j = 0; j < e.h; j++, src += srcp, dst += dstp)
{
memcpy(dst, src, LineWidths[j + e.y] * sizeof(*dst));
}
f.Width = w;
f.Height = e.h;
}
static const char *DeviceNames[] =
{
"none",
"gamepad",
"3dpad",
"mouse",
"wheel",
"mission",
"dmission",
"keyboard"};
EXPORT void SetupInput(const int *portdevices, const int *multitaps)
{
for (int i = 0; i < 2; i++)
SMPC_SetMultitap(i, multitaps[i]);
for (int i = 0; i < 12; i++)
SMPC_SetInput(i, DeviceNames[portdevices[i]], ControllerInput + i * 32);
}
void (*InputCallback)();
EXPORT void SetInputCallback(void (*callback)())
{
InputCallback = callback;
}
static std::vector<MemoryArea> MemoryAreas;
void AddMemoryDomain(const char *name, const void *ptr, int size, int flags)
{
MemoryArea m;
m.Data = (void*)ptr;
m.Name = name;
m.Size = size;
m.Flags = flags;
MemoryAreas.push_back(m);
}
EXPORT void GetMemoryAreas(MemoryArea* m)
{
memcpy(m, MemoryAreas.data(), MemoryAreas.size() * sizeof(MemoryArea));
}
EXPORT void SetRtc(int64 ticks, int language)
{
time_t time = ticks;
const struct tm *tm = gmtime(&time);
SMPC_SetRTC(tm, language);
}
namespace MDFN_IEN_SS
{
extern bool CorrectAspect;
extern bool ShowHOverscan;
extern bool DoHBlend;
extern int LineVisFirst;
extern int LineVisLast;
}
EXPORT void SetVideoParameters(bool correctAspect, bool hBlend, bool hOverscan, int sls, int sle)
{
CorrectAspect = correctAspect;
ShowHOverscan = hOverscan;
DoHBlend = hBlend;
LineVisFirst = sls;
LineVisLast = sle;
}
// if (BackupRAM_Dirty)SaveBackupRAM();
// if (CART_GetClearNVDirty())SaveCartNV();
/*static MDFN_COLD void CloseGame(void)
{
try { SaveBackupRAM(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
try { SaveCartNV(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
try { SaveRTC(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
Cleanup();
}*/
/*
static MDFN_COLD void BackupCartNV(void)
{
const char* ext = nullptr;
void* nv_ptr = nullptr;
uint64 nv_size = 0;
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
if(ext)
MDFN_BackupSavFile(10, ext);
}*/
/*static MDFN_COLD void LoadCartNV(void)
{
const char* ext = nullptr;
void* nv_ptr = nullptr;
uint64 nv_size = 0;
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
if(ext)
{
//FileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), FileStream::MODE_READ);
GZFileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), GZFileStream::MODE::READ);
nvs.read(nv_ptr, nv_size);
}
}
static MDFN_COLD void SaveCartNV(void)
{
const char* ext = nullptr;
void* nv_ptr = nullptr;
uint64 nv_size = 0;
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
if(ext)
{
//FileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), FileStream::MODE_WRITE_INPLACE);
GZFileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), GZFileStream::MODE::WRITE);
nvs.write(nv_ptr, nv_size);
nvs.close();
}
}*/
/*static MDFN_COLD void SaveRTC(void)
{
FileStream sds(MDFN_MakeFName(MDFNMKF_SAV, 0, "smpc"), FileStream::MODE_WRITE_INPLACE);
SMPC_SaveNV(&sds);
sds.close();
}
static MDFN_COLD void LoadRTC(void)
{
FileStream sds(MDFN_MakeFName(MDFNMKF_SAV, 0, "smpc"), FileStream::MODE_READ);
SMPC_LoadNV(&sds);
}*/
int main()
{
return 0;
}

View File

@ -1,171 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* cart.cpp - Expansion cart emulation
** Copyright (C) 2016-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "ss.h"
#include "cart.h"
#include "cart/backup.h"
#include "cart/cs1ram.h"
#include "cart/debug.h"
#include "cart/extram.h"
//#include "cart/nlmodem.h"
#include "cart/rom.h"
namespace MDFN_IEN_SS
{
CartInfo Cart;
template<typename T>
static MDFN_HOT void DummyRead(uint32 A, uint16* DB)
{
// Don't set *DB here.
SS_DBG(SS_DBG_WARNING, "[CART] Unknown %zu-byte read from 0x%08x\n", sizeof(T), A);
}
template<typename T>
static MDFN_HOT void DummyWrite(uint32 A, uint16* DB)
{
SS_DBG(SS_DBG_WARNING, "[CART] Unknown %zu-byte write to 0x%08x(DB=0x%04x)\n", sizeof(T), A, *DB);
}
static sscpu_timestamp_t DummyUpdate(sscpu_timestamp_t timestamp)
{
return SS_EVENT_DISABLED_TS;
}
static void DummyAdjustTS(const int32 delta)
{
}
static void DummySetCPUClock(const int32 master_clock, const int32 divider)
{
}
static MDFN_COLD void DummyReset(bool powering_up)
{
}
static MDFN_COLD bool DummyGetClearNVDirty(void)
{
return false;
}
static MDFN_COLD void DummyGetNVInfo(const char** ext, void** nv_ptr, uint64* nv_size)
{
*ext = nullptr;
*nv_ptr = nullptr;
*nv_size = 0;
}
void CartInfo::CS01_SetRW8W16(uint32 Astart, uint32 Aend, void (*r16)(uint32 A, uint16* DB), void (*w8)(uint32 A, uint16* DB), void (*w16)(uint32 A, uint16* DB))
{
assert(Astart >= 0x02000000 && Aend <= 0x04FFFFFF);
assert(!(Astart & ((1U << 20) - 1)));
assert(!((Aend + 1) & ((1U << 20) - 1)));
for(unsigned i = (Astart - 0x02000000) >> 20; i <= (Aend - 0x02000000) >> 20; i++)
{
auto& rw = Cart.CS01_RW[i];
if(r16) rw.Read16 = r16;
if(w8) rw.Write8 = w8;
if(w16) rw.Write16 = w16;
}
}
void CartInfo::CS2M_SetRW8W16(uint8 Ostart, uint8 Oend, void (*r16)(uint32 A, uint16* DB), void (*w8)(uint32 A, uint16* DB), void (*w16)(uint32 A, uint16* DB))
{
assert(!(Ostart & 0x1));
assert(Oend & 0x1);
assert(Ostart < 0x40);
assert(Oend < 0x40);
for(int i = Ostart >> 1; i <= Oend >> 1; i++)
{
auto& rw = Cart.CS2M_RW[i];
if(r16) rw.Read16 = r16;
if(w8) rw.Write8 = w8;
if(w16) rw.Write16 = w16;
}
}
void CART_Init(const int cart_type)
{
Cart.CS01_SetRW8W16(0x02000000, 0x04FFFFFF, DummyRead<uint16>, DummyWrite<uint8>, DummyWrite<uint16>);
Cart.CS2M_SetRW8W16(0x00, 0x3F, DummyRead<uint16>, DummyWrite<uint8>, DummyWrite<uint16>);
Cart.Reset = DummyReset;
Cart.GetNVInfo = DummyGetNVInfo;
Cart.GetClearNVDirty = DummyGetClearNVDirty;
Cart.EventHandler = DummyUpdate;
Cart.AdjustTS = DummyAdjustTS;
Cart.SetCPUClock = DummySetCPUClock;
switch(cart_type)
{
default:
case CART_NONE:
break;
case CART_BACKUP_MEM:
CART_Backup_Init(&Cart);
break;
case CART_EXTRAM_1M:
case CART_EXTRAM_4M:
CART_ExtRAM_Init(&Cart, cart_type == CART_EXTRAM_4M);
break;
case CART_KOF95:
case CART_ULTRAMAN:
{
CART_ROM_Init(&Cart, cart_type == CART_KOF95 ? "ss.cart.kof95_path" : "ss.cart.ultraman_path");
}
break;
case CART_CS1RAM_16M:
CART_CS1RAM_Init(&Cart);
break;
case CART_MDFN_DEBUG:
CART_Debug_Init(&Cart);
break;
// case CART_NLMODEM:
// CART_NLModem_Init(&Cart);
// break;
}
for(auto& m : Cart.CS01_RW)
assert(m.Read16 != nullptr && m.Write8 != nullptr && m.Write16 != nullptr);
for(auto& m : Cart.CS2M_RW)
assert(m.Read16 != nullptr && m.Write8 != nullptr && m.Write16 != nullptr);
}
}

View File

@ -1,95 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* cart.h - Expansion cart emulation
** Copyright (C) 2016-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_CART_H
#define __MDFN_SS_CART_H
namespace MDFN_IEN_SS
{
struct CartInfo
{
void (*Reset)(bool powering_up);
void (*GetNVInfo)(const char** ext, void** nv_ptr, uint64* nv_size);
bool (*GetClearNVDirty)(void);
void (*AdjustTS)(const int32 delta);
// For calculating clock ratios.
void (*SetCPUClock)(const int32 master_clock, const int32 cpu_divider);
ss_event_handler EventHandler;
// A >> 20
struct
{
void (*Read16)(uint32 A, uint16* DB);
void (*Write8)(uint32 A, uint16* DB);
void (*Write16)(uint32 A, uint16* DB);
} CS01_RW[0x30];
struct
{
void (*Read16)(uint32 A, uint16* DB);
void (*Write8)(uint32 A, uint16* DB);
void (*Write16)(uint32 A, uint16* DB);
} CS2M_RW[0x20];
void CS01_SetRW8W16(uint32 Astart, uint32 Aend, void (*r16)(uint32 A, uint16* DB), void (*w8)(uint32 A, uint16* DB) = nullptr, void (*w16)(uint32 A, uint16* DB) = nullptr);
void CS2M_SetRW8W16(uint8 Ostart, uint8 Oend, void (*r16)(uint32 A, uint16* DB), void (*w8)(uint32 A, uint16* DB) = nullptr, void (*w16)(uint32 A, uint16* DB) = nullptr);
};
static INLINE void CART_CS01_Read16_DB(uint32 A, uint16* DB) { extern CartInfo Cart; Cart.CS01_RW[(size_t)(A >> 20) - (0x02000000 >> 20)].Read16 (A, DB); }
static INLINE void CART_CS01_Write8_DB(uint32 A, uint16* DB) { extern CartInfo Cart; Cart.CS01_RW[(size_t)(A >> 20) - (0x02000000 >> 20)].Write8 (A, DB); }
static INLINE void CART_CS01_Write16_DB(uint32 A, uint16* DB) { extern CartInfo Cart; Cart.CS01_RW[(size_t)(A >> 20) - (0x02000000 >> 20)].Write16(A, DB); }
static INLINE void CART_CS2_Read16_DB(uint32 A, uint16* DB) { extern CartInfo Cart; Cart.CS2M_RW[(A >> 1) & 0x1F].Read16 (A, DB); }
static INLINE void CART_CS2_Write8_DB(uint32 A, uint16* DB) { extern CartInfo Cart; Cart.CS2M_RW[(A >> 1) & 0x1F].Write8 (A, DB); }
static INLINE void CART_CS2_Write16_DB(uint32 A, uint16* DB) { extern CartInfo Cart; Cart.CS2M_RW[(A >> 1) & 0x1F].Write16(A, DB); }
enum
{
CART__RESERVED = -1,
CART_NONE = 0,
CART_BACKUP_MEM,
CART_EXTRAM_1M,
CART_EXTRAM_4M,
CART_KOF95,
CART_ULTRAMAN,
CART_CS1RAM_16M,
CART_NLMODEM,
CART_MDFN_DEBUG
};
void CART_Init(const int cart_type) MDFN_COLD;
static INLINE ss_event_handler CART_GetEventHandler(void) { extern CartInfo Cart; return Cart.EventHandler; }
static INLINE void CART_AdjustTS(const int32 delta) { extern CartInfo Cart; Cart.AdjustTS(delta); }
static INLINE void CART_SetCPUClock(const int32 master_clock, const int32 cpu_divider) { extern CartInfo Cart; Cart.SetCPUClock(master_clock, cpu_divider); }
static INLINE void CART_GetNVInfo(const char** ext, void** nv_ptr, uint64* nv_size) { extern CartInfo Cart; Cart.GetNVInfo(ext, nv_ptr, nv_size); }
static INLINE bool CART_GetClearNVDirty(void) { extern CartInfo Cart; return Cart.GetClearNVDirty(); }
static INLINE void CART_Reset(bool powering_up) { extern CartInfo Cart; Cart.Reset(powering_up); }
}
#endif

View File

@ -1,91 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* backup.cpp - Backup memory(512KiB) cart emulation
** Copyright (C) 2016-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "backup.h"
namespace MDFN_IEN_SS
{
static uint8 *ExtBackupRAM;
static bool ExtBackupRAM_Dirty;
// TODO: Check mirroring.
template <typename T, bool IsWrite>
static MDFN_HOT void ExtBackupRAM_RW_DB(uint32 A, uint16 *DB)
{
uint8 *const ptr = ExtBackupRAM + ((A >> 1) & 0x7FFFF);
if (IsWrite)
{
if (A & 1)
{
ExtBackupRAM_Dirty = true;
*ptr = *DB;
}
}
else
{
*DB = (*ptr << 0) | 0xFF00;
if ((A & ~1) == 0x04FFFFFE)
*DB = 0x21;
}
}
static MDFN_COLD bool GetClearNVDirty(void)
{
bool ret = ExtBackupRAM_Dirty;
ExtBackupRAM_Dirty = false;
return ret;
}
static MDFN_COLD void GetNVInfo(const char **ext, void **nv_ptr, uint64 *nv_size)
{
*ext = "bcr";
*nv_ptr = ExtBackupRAM;
*nv_size = 524288;
}
void CART_Backup_Init(CartInfo *c)
{
static const uint8 init[0x10] = {0x42, 0x61, 0x63, 0x6B, 0x55, 0x70, 0x52, 0x61, 0x6D, 0x20, 0x46, 0x6F, 0x72, 0x6D, 0x61, 0x74};
ExtBackupRAM = (uint8 *)alloc_plain(524288);
memset(ExtBackupRAM, 0x00, 524288);
for (unsigned i = 0; i < 0x200; i += 0x10)
memcpy(ExtBackupRAM + i, init, 0x10);
ExtBackupRAM_Dirty = false;
c->CS01_SetRW8W16(0x04000000, 0x04FFFFFF,
ExtBackupRAM_RW_DB<uint16, false>,
ExtBackupRAM_RW_DB<uint8, true>,
ExtBackupRAM_RW_DB<uint16, true>);
c->GetClearNVDirty = GetClearNVDirty;
c->GetNVInfo = GetNVInfo;
AddMemoryDomain("Backup Cart", ExtBackupRAM, 524288, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_SAVERAMMABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
}
}

View File

@ -1,30 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* backup.h - Backup memory(512KiB) cart emulation
** Copyright (C) 2016-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_CART_BACKUP_H
#define __MDFN_SS_CART_BACKUP_H
namespace MDFN_IEN_SS
{
void CART_Backup_Init(CartInfo* c) MDFN_COLD;
}
#endif

View File

@ -1,3 +0,0 @@
#include "../ss.h"
#include "../cart.h"

View File

@ -1,60 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* cs1ram.cpp - CS1 RAM(16MiB) cart emulation
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "cs1ram.h"
namespace MDFN_IEN_SS
{
static uint16 *CS1RAM = nullptr;
template <typename T, bool IsWrite>
static MDFN_HOT void CS1RAM_RW_DB(uint32 A, uint16 *DB)
{
const uint32 mask = (sizeof(T) == 2) ? 0xFFFF : (0xFF << (((A & 1) ^ 1) << 3));
uint16 *const ptr = (uint16 *)((uint8 *)CS1RAM + (A & 0x00FFFFFE));
if (IsWrite)
*ptr = (*ptr & ~mask) | (*DB & mask);
else
*DB = *ptr;
}
static MDFN_COLD void Reset(bool powering_up)
{
if (powering_up)
memset(CS1RAM, 0, 0x1000000);
}
void CART_CS1RAM_Init(CartInfo *c)
{
CS1RAM = (uint16 *)alloc_plain(0x1000000);
SS_SetPhysMemMap(0x04000000, 0x04FFFFFF, CS1RAM, 0x1000000, true);
c->CS01_SetRW8W16(0x04000000, 0x04FFFFFF,
CS1RAM_RW_DB<uint16, false>,
CS1RAM_RW_DB<uint8, true>,
CS1RAM_RW_DB<uint16, true>);
c->Reset = Reset;
AddMemoryDomain("CS1 Cart", CS1RAM, 0x1000000, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
}
}

View File

@ -1,30 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* cs1ram.h - CS1 RAM(16MiB) cart emulation
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_CART_CS1RAM_H
#define __MDFN_SS_CART_CS1RAM_H
namespace MDFN_IEN_SS
{
void CART_CS1RAM_Init(CartInfo* c) MDFN_COLD;
}
#endif

View File

@ -1,60 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* debug.cpp - Mednafen debug cart emulation
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "debug.h"
namespace MDFN_IEN_SS
{
template<typename T, bool IsWrite>
static void Debug_RW_DB(uint32 A, uint16* DB)
{
//
// printf-related debugging
//
if((A &~ 0x3) == 0x02100000)
{
if(IsWrite)
{
if(A == 0x02100001)
{
fputc(*DB, stderr);
fflush(stderr);
}
}
else
*DB = 0;
return;
}
}
void CART_Debug_Init(CartInfo* c)
{
c->CS01_SetRW8W16(0x02100000, /*0x02100001*/ 0x021FFFFF,
Debug_RW_DB<uint16, false>,
Debug_RW_DB<uint8, true>,
Debug_RW_DB<uint16, true>);
}
}

View File

@ -1,30 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* debug.h - Mednafen debug cart emulation
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_CART_DEBUG_H
#define __MDFN_SS_CART_DEBUG_H
namespace MDFN_IEN_SS
{
void CART_Debug_Init(CartInfo* c) MDFN_COLD;
}
#endif

View File

@ -1,84 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* extram.cpp - Extended RAM(1MiB and 4MiB) cart emulation
** Copyright (C) 2016-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "extram.h"
namespace MDFN_IEN_SS
{
static uint16 *ExtRAM; //[0x200000];
static size_t ExtRAM_Mask;
static uint8 Cart_ID;
template <typename T, bool IsWrite>
static MDFN_HOT void ExtRAM_RW_DB(uint32 A, uint16 *DB)
{
const uint32 mask = (sizeof(T) == 2) ? 0xFFFF : (0xFF << (((A & 1) ^ 1) << 3));
uint16 *const ptr = (uint16 *)((uint8 *)ExtRAM + (A & ExtRAM_Mask));
//printf("Barf %zu %d: %08x\n", sizeof(T), IsWrite, A);
if (IsWrite)
*ptr = (*ptr & ~mask) | (*DB & mask);
else
*DB = *ptr;
}
static MDFN_HOT void CartID_Read_DB(uint32 A, uint16 *DB)
{
if ((A & ~1) == 0x04FFFFFE)
*DB = Cart_ID;
}
static MDFN_COLD void Reset(bool powering_up)
{
if (powering_up)
memset(ExtRAM, 0, 0x400000); // TODO: Test.
}
void CART_ExtRAM_Init(CartInfo *c, bool R4MiB)
{
ExtRAM = (uint16 *)alloc_plain(0x400000);
if (R4MiB)
{
Cart_ID = 0x5C;
ExtRAM_Mask = 0x3FFFFE;
}
else
{
Cart_ID = 0x5A;
ExtRAM_Mask = 0x27FFFE;
}
SS_SetPhysMemMap(0x02400000, 0x025FFFFF, ExtRAM + (0x000000 / sizeof(uint16)), (R4MiB ? 0x200000 : 0x080000), true);
SS_SetPhysMemMap(0x02600000, 0x027FFFFF, ExtRAM + (0x200000 / sizeof(uint16)), (R4MiB ? 0x200000 : 0x080000), true);
c->CS01_SetRW8W16(0x02400000, 0x027FFFFF,
ExtRAM_RW_DB<uint16, false>,
ExtRAM_RW_DB<uint8, true>,
ExtRAM_RW_DB<uint16, true>);
c->CS01_SetRW8W16(/*0x04FFFFFE*/ 0x04F00000, 0x04FFFFFF, CartID_Read_DB);
c->Reset = Reset;
AddMemoryDomain("Ram Cart", ExtRAM, 0x400000, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
}
}

View File

@ -1,30 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* extram.h - Extended RAM(1MiB and 4MiB) cart emulation
** Copyright (C) 2016-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_CART_EXTRAM_H
#define __MDFN_SS_CART_EXTRAM_H
namespace MDFN_IEN_SS
{
void CART_ExtRAM_Init(CartInfo* c, bool R4MiB) MDFN_COLD;
}
#endif

View File

@ -1,53 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* rom.cpp - ROM cart emulation
** Copyright (C) 2016-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "rom.h"
namespace MDFN_IEN_SS
{
static uint16 *ROM; //[0x100000];
static MDFN_HOT void ROM_Read(uint32 A, uint16 *DB)
{
// TODO: Check mirroring.
//printf("ROM: %08x\n", A);
*DB = *(uint16 *)((uint8 *)ROM + (A & 0x1FFFFE));
}
void CART_ROM_Init(CartInfo *c, const char *filename)
{
if (FirmwareSizeCallback(filename) != 0x200000)
abort();
ROM = (uint16 *)alloc_sealed(0x200000);
FirmwareDataCallback(filename, (uint8 *)ROM);
for (unsigned i = 0; i < 0x100000; i++)
{
ROM[i] = MDFN_de16msb<true>(&ROM[i]);
}
SS_SetPhysMemMap(0x02000000, 0x03FFFFFF, ROM, 0x200000, false);
c->CS01_SetRW8W16(0x02000000, 0x03FFFFFF, ROM_Read);
AddMemoryDomain("Rom Cart", ROM, 0x200000, MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
}
}

View File

@ -1,30 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* rom.h - ROM cart emulation
** Copyright (C) 2016-2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_CART_ROM_H
#define __MDFN_SS_CART_ROM_H
namespace MDFN_IEN_SS
{
void CART_ROM_Init(CartInfo* c, const char* filename) MDFN_COLD;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* cdb.h:
** Copyright (C) 2015-2016 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_CDB_H
#define __MDFN_SS_CDB_H
class CDIF;
namespace MDFN_IEN_SS
{
void CDB_Init(void) MDFN_COLD;
void CDB_SetDisc(bool tray_open, CDIF *cdif) MDFN_COLD;
void CDB_Write_DBM(uint32 offset, uint16 DB, uint16 mask) MDFN_HOT;
uint16 CDB_Read(uint32 offset) MDFN_HOT;
void CDB_Reset(bool powering_up) MDFN_COLD;
sscpu_timestamp_t CDB_Update(sscpu_timestamp_t timestamp);
void CDB_ResetTS(void);
void CDB_GetCDDA(uint16* outbuf); // writes to outbuf[0] and outbuf[1]
void CDB_SetClockRatio(uint32 ratio);
void CDB_ResetCD(void);
void CDB_SetCDActive(bool active);
}
#endif

View File

@ -1,430 +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 "../defs.h"
#include "CDUtility.h"
#include "dvdisaster.h"
#include "lec.h"
#include <assert.h>
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[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(int i = 0; i < 96; i++)
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
}
void synth_leadout_sector_lba(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(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
//
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf)
{
uint8 buf[0xC];
uint32 lba_relative;
uint32 ma, sa, fa;
uint32 m, s, f;
if(lba < -150 || lba >= 0)
printf("[BUG] subpw_synth_udapp_lba() lba out of range --- %d\n", lba);
{
int32 lba_tmp = lba + lba_subq_relative_offs;
if(lba_tmp < 0)
lba_relative = 0 - 1 - lba_tmp;
else
lba_relative = lba_tmp - 0;
}
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;
if(toc.disc_type == DISC_TYPE_CD_I && toc.first_track > 1)
control = 0x4;
else if(toc.tracks[toc.first_track].valid)
control = toc.tracks[toc.first_track].control;
else
control = 0x0;
memset(buf, 0, 0xC);
buf[0] = (adr << 0) | (control << 4);
buf[1] = U8_to_BCD(toc.first_track);
buf[2] = U8_to_BCD(0x00);
// 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_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf)
{
memset(out_buf, 0, 2352 + 96);
subpw_synth_udapp_lba(toc, lba, lba_subq_relative_offs, 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;
}
}
}
#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,237 +0,0 @@
#ifndef __MDFN_CDROM_CDUTILITY_H
#define __MDFN_CDROM_CDUTILITY_H
namespace CDUtility
{
// 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) MDFN_COLD;
// 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
{
ADR_NOQINFO = 0x00,
ADR_CURPOS = 0x01,
ADR_MCN = 0x02,
ADR_ISRC = 0x03
};
struct TOC_Track
{
uint8 adr;
uint8 control;
uint32 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
{
DISC_TYPE_CDDA_OR_M1 = 0x00,
DISC_TYPE_CD_I = 0x10,
DISC_TYPE_CD_XA = 0x20
};
struct TOC
{
INLINE TOC()
{
Clear();
}
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) const
{
int32 lvt = 0;
for(int32 track = 1; track <= 100; track++)
{
if(!tracks[track].valid)
continue;
if(LBA < tracks[track].lba)
break;
lvt = track;
}
return(lvt);
}
uint8 first_track;
uint8 last_track;
uint8 disc_type;
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
};
//
// 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
// User data area pre-pause(MSF 00:00:00 through 00:01:74), lba -150 through -1
// out_buf must be able to contain 2352+96 bytes.
// "mode" is not used if the area is to be encoded as audio.
// pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.
void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf);
void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf);
// out_buf must be able to contain 2352+96 bytes.
// "mode" is not used if the area is to be encoded as audio.
// pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.
void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf);
//
// 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.
//
// Note: mode 2 form 1 L-EC data can't correct errors in the 4-byte sector header(address + mode),
// but the error(s) will still be detected by EDC.
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);
}
#endif

View File

@ -1,131 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* 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 "../ss.h"
#include <string.h>
#include <sys/types.h>
#include "cdromif.h"
//#include "CDAccess.h"
//#include "../general.h"
#include <algorithm>
using namespace CDUtility;
enum
{
// Status/Error messages
CDIF_MSG_DONE = 0, // Read -> emu. args: No args.
CDIF_MSG_INFO, // Read -> emu. args: str_message
CDIF_MSG_FATAL_ERROR, // Read -> emu. args: *TODO ARGS*
//
// Command messages.
//
CDIF_MSG_DIEDIEDIE, // Emu -> read
CDIF_MSG_READ_SECTOR, /* Emu -> read
args[0] = lba
*/
};
typedef struct
{
bool valid;
bool error;
int32 lba;
uint8 data[2352 + 96];
} CDIF_Sector_Buffer;
CDIF::CDIF() : UnrecoverableError(false)
{
}
CDIF::~CDIF()
{
}
bool CDIF::ValidateRawSector(uint8 *buf)
{
int mode = buf[12 + 3];
if(mode != 0x1 && mode != 0x2)
return(false);
if(!edc_lec_check_and_correct(buf, mode == 2))
return(false);
return(true);
}
int CDIF::ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message)
{
int ret = 0;
if(UnrecoverableError)
return(false);
while(sector_count--)
{
uint8 tmpbuf[2352 + 96];
if(!ReadRawSector(tmpbuf, lba))
{
puts("CDIF Raw Read error");
return(FALSE);
}
if(!ValidateRawSector(tmpbuf))
{
/*if(!suppress_uncorrectable_message)
{
MDFN_DispMessage(_("Uncorrectable data at sector %d"), lba);
MDFN_PrintError(_("Uncorrectable data at sector %d"), lba);
}*/
return(false);
}
const int mode = tmpbuf[12 + 3];
if(!ret)
ret = mode;
if(mode == 1)
{
memcpy(buf, &tmpbuf[12 + 4], 2048);
}
else if(mode == 2)
{
memcpy(buf, &tmpbuf[12 + 4 + 8], 2048);
}
else
{
printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba);
return(false);
}
buf += 2048;
lba++;
}
return(ret);
}

View File

@ -1,59 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* 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
*/
#ifndef __MDFN_CDROM_CDROMIF_H
#define __MDFN_CDROM_CDROMIF_H
#include "CDUtility.h"
#include <queue>
typedef CDUtility::TOC CD_TOC;
class CDIF
{
public:
CDIF();
virtual ~CDIF();
static const int32 LBA_Read_Minimum = -150;
static const int32 LBA_Read_Maximum = 449849; // 100 * 75 * 60 - 150 - 1
inline void ReadTOC(CDUtility::TOC *read_target)
{
*read_target = disc_toc;
}
virtual void HintReadSector(int32 lba) = 0;
virtual bool ReadRawSector(uint8 *buf, int32 lba) = 0; // Reads 2352+96 bytes of data into buf.
virtual bool ReadRawSectorPWOnly(uint8* pwbuf, int32 lba, bool hint_fullread) = 0; // Reads 96 bytes(of raw subchannel PW data) into pwbuf.
// Call for mode 1 or mode 2 form 1 only.
bool ValidateRawSector(uint8 *buf);
// Utility/Wrapped functions
// Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
// Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
int ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message = false);
protected:
bool UnrecoverableError;
CDUtility::TOC disc_toc;
};
#endif

View File

@ -1,130 +0,0 @@
/* 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 "dvdisaster.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". */
/* */
/*****************************************************************/
static const 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 EDCCrc32(const unsigned char *data, int len)
{
uint32 crc = 0;
while(len--)
crc = edctable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
return crc;
}

View File

@ -1,171 +0,0 @@
/* 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
*
* 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.
*/
#ifndef DVDISASTER_H
#define DVDISASTER_H
/* "Dare to be gorgeous and unique.
* But don't ever be cryptic or otherwise unfathomable.
* Make it unforgettably great."
*
* From "A Final Note on Style",
* Amiga Intuition Reference Manual, 1986, p. 231
*/
/***
*** I'm too lazy to mess with #include dependencies.
*** Everything #includeable is rolled up herein...
*/
#include "../ss.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/***
*** dvdisaster.c
***/
void PrepareDeadSector(void);
void CreateEcc(void);
void FixEcc(void);
void Verify(void);
uint32 EDCCrc32(const unsigned char*, int);
/***
*** galois.c
***
* This is currently the hardcoded GF(2**8).
* int32 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 gfGenerator; /* GF generator polynomial */
int32 *indexOf; /* log */
int32 *alphaTo; /* inverse log */
int32 *encAlphaTo; /* inverse log optimized for encoder */
} GaloisTables;
/* Lookup and working tables for the ReedSolomon codecs */
typedef struct _ReedSolomonTables
{ GaloisTables *gfTables;/* from above */
int32 *gpoly; /* RS code generator polynomial */
int32 fcr; /* first consecutive root of RS generator polynomial */
int32 primElem; /* primitive field element */
int32 nroots; /* degree of RS generator polynomial */
int32 ndata; /* data bytes per ecc block */
} ReedSolomonTables;
GaloisTables* CreateGaloisTables(int32);
void FreeGaloisTables(GaloisTables*);
ReedSolomonTables *CreateReedSolomonTables(GaloisTables*, int32, int32, int);
void FreeReedSolomonTables(ReedSolomonTables*);
/***
*** l-ec.c
***/
#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*);
/***
*** misc.c
***/
char* sgettext(char*);
char* sgettext_utf8(char*);
int64 uchar_to_int64(unsigned char*);
void int64_to_uchar(unsigned char*, int64);
void CalcSectors(int64, int64*, int*);
/***
*** recover-raw.c
***/
#define CD_RAW_SECTOR_SIZE 2352
#define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */
int CheckEDC(const unsigned char*, bool);
int CheckMSF(unsigned char*, int);
int ValidateRawSector(unsigned char *frame, bool xaMode);
bool Init_LEC_Correct(void);
#endif /* DVDISASTER_H */

Some files were not shown because too many files have changed in this diff Show More