ss and pcfx dirs can be whacked (they belong to numa now)
This commit is contained in:
parent
602dec0c4c
commit
316aafed40
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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;
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -1,309 +0,0 @@
|
|||
static uint8 MDFN_FASTCALL port_rbyte(v810_timestamp_t ×tamp, 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 ×tamp, 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 ×tamp, 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 ×tamp, 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);
|
||||
}
|
||||
}
|
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 ×tamp, 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 ×tamp, 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 ×tamp, 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 ×tamp, 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 ×tamp, 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 ×tamp, 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);
|
||||
}
|
||||
}
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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 },
|
|
@ -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 },
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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] );
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
@ -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 ×tamp, uint32 A);
|
||||
uint16 MDFN_FASTCALL (*MemRead16)(v810_timestamp_t ×tamp, uint32 A);
|
||||
uint32 MDFN_FASTCALL (*MemRead32)(v810_timestamp_t ×tamp, uint32 A);
|
||||
|
||||
void MDFN_FASTCALL (*MemWrite8)(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
||||
void MDFN_FASTCALL (*MemWrite16)(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
||||
void MDFN_FASTCALL (*MemWrite32)(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
||||
|
||||
uint8 MDFN_FASTCALL (*IORead8)(v810_timestamp_t ×tamp, uint32 A);
|
||||
uint16 MDFN_FASTCALL (*IORead16)(v810_timestamp_t ×tamp, uint32 A);
|
||||
uint32 MDFN_FASTCALL (*IORead32)(v810_timestamp_t ×tamp, uint32 A);
|
||||
|
||||
void MDFN_FASTCALL (*IOWrite8)(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
||||
void MDFN_FASTCALL (*IOWrite16)(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
||||
void MDFN_FASTCALL (*IOWrite32)(v810_timestamp_t ×tamp, 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 ×tamp, int sub_op, int arg1);
|
||||
void fpu_subop(v810_timestamp_t ×tamp, 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 ×tamp, uint32 A, uint32 V);
|
||||
uint32 CacheOpMemLoad(v810_timestamp_t ×tamp, uint32 A);
|
||||
|
||||
void CacheClear(v810_timestamp_t ×tamp, uint32 start, uint32 count);
|
||||
void CacheDump(v810_timestamp_t ×tamp, const uint32 SA);
|
||||
void CacheRestore(v810_timestamp_t ×tamp, const uint32 SA);
|
||||
|
||||
uint32 RDCACHE(v810_timestamp_t ×tamp, uint32 addr);
|
||||
//
|
||||
// End caching related
|
||||
//
|
||||
|
||||
uint16 RDOP(v810_timestamp_t ×tamp, uint32 addr, uint32 meow = 2);
|
||||
void SetFlag(uint32 n, bool condition);
|
||||
void SetSZ(uint32 value);
|
||||
|
||||
void SetSREG(v810_timestamp_t ×tamp, 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 ×tamp, uint32 A);
|
||||
void BSTR_WWORD(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
||||
bool Do_BSTR_Search(v810_timestamp_t ×tamp, const int inc_mul, unsigned int bit_test);
|
||||
|
||||
V810_FP_Ops fpo;
|
||||
|
||||
uint8 DummyRegion[V810_FAST_MAP_PSIZE + V810_FAST_MAP_TRAMPOLINE_SIZE];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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();
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
#include "../ss.h"
|
||||
#include "../cart.h"
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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>);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
3630
waterbox/ss/cdb.cpp
3630
waterbox/ss/cdb.cpp
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue