Integrated pfce_fast now too - can compile pce_fast now in same

repo
This commit is contained in:
twinaphex 2012-10-21 01:47:02 +02:00
parent e1b305a8b4
commit dc4236c507
76 changed files with 114824 additions and 28 deletions

View File

@ -28,8 +28,8 @@ ifeq ($(core), psx)
PTHREAD_FLAGS = -pthread
NEED_CD = 1
NEED_THREADING = 1
NEED_BPP = 32
CORE_DEFINE := -DWANT_PSX_EMU
CORE_INCDIR := -I$(MEDNAFEN_DIR)/psx
CORE_DIR := $(MEDNAFEN_DIR)/psx
CORE_SOURCES := $(CORE_DIR)/psx.cpp \
$(CORE_DIR)/irq.cpp \
@ -58,12 +58,33 @@ SSE_DEFINES := -msse -msse2
else ifeq ($(core), pce_fast)
core = pce_fast
PTHREAD_FLAGS = -pthread
NEED_BPP = 16
NEED_CD = 1
NEED_CRC32 = 1
NEED_THREADING = 1
CORE_DIR := $(MEDNAFEN_DIR)/pce_fast
CORE_DEFINE := -DWANT_PCE_FAST_EMU
CORE_DIR := $(MEDNAFEN_DIR)/pce_fast-0924
CORE_SOURCES := $(CORE_DIR)/huc.cpp \
$(CORE_DIR)/pce_huc6280.cpp \
$(CORE_DIR)/input.cpp \
$(CORE_DIR)/pce.cpp \
$(CORE_DIR)/tsushin.cpp \
$(CORE_DIR)/input/gamepad.cpp \
$(CORE_DIR)/input/mouse.cpp \
$(CORE_DIR)/input/tsushinkb.cpp \
$(CORE_DIR)/vdc.cpp
TARGET_NAME := mednafen_pce_fast_libretro
HW_CPU_SOURCES += $(MEDNAFEN_DIR)/hw_cpu/huc6280/huc6280.cpp
HW_MISC_SOURCES += $(MEDNAFEN_DIR)/hw_misc/arcade_card/arcade_card.cpp
HW_SOUND_SOURCES += $(MEDNAFEN_DIR)/hw_sound/pce_psg/pce_psg.cpp
HW_VIDEO_SOURCES += $(MEDNAFEN_DIR)/hw_video/huc6270/vdc.cpp
CDROM_SOURCES += $(MEDNAFEN_DIR)/cdrom/pcecd.cpp
endif
CORE_INCDIR := -I$(CORE_DIR)
ifeq ($(platform), unix)
TARGET := $(TARGET_NAME).so
fpic := -fPIC
@ -135,7 +156,11 @@ else
endif
ifeq ($(NEED_THREADING), 1)
THREAD_STUBS := thread.cpp stubs_thread.cpp
THREAD_STUBS += thread.cpp stubs_thread.cpp
endif
ifeq ($(NEED_CRC32), 1)
FLAGS += -DHAVE_CRC32
endif
ifeq ($(NEED_CD), 1)
@ -150,7 +175,7 @@ CDROM_SOURCES += $(MEDNAFEN_DIR)/cdrom/CDAccess.cpp \
$(MEDNAFEN_DIR)/cdrom/scsicd.cpp \
$(MEDNAFEN_DIR)/cdrom/recover-raw.cpp \
$(MEDNAFEN_DIR)/cdrom/l-ec.cpp \
$(MEDNAFEN_DIR)/cdrom/crc32.cpp
$(MEDNAFEN_DIR)/cdrom/cd_crc32.cpp
MPC_SRC := $(wildcard $(MEDNAFEN_DIR)/mpcdec/*.c)
TREMOR_SRC := $(wildcard $(MEDNAFEN_DIR)/tremor/*.c)
@ -190,7 +215,7 @@ SOURCES_C := $(MEDNAFEN_DIR)/trio/trio.c \
$(MEDNAFEN_DIR)/trio/trionan.c \
$(MEDNAFEN_DIR)/trio/triostr.c
SOURCES := $(LIBRETRO_SOURCES) $(CORE_SOURCES) $(MEDNAFEN_SOURCES)
SOURCES := $(LIBRETRO_SOURCES) $(CORE_SOURCES) $(MEDNAFEN_SOURCES) $(HW_CPU_SOURCES) $(HW_MISC_SOURCES) $(HW_SOUND_SOURCES) $(HW_VIDEO_SOURCES)
OBJECTS := $(SOURCES:.cpp=.o) $(SOURCES_C:.c=.o)
all: $(TARGET)
@ -223,6 +248,14 @@ ifeq ($(CACHE_CD), 1)
FLAGS += -D__LIBRETRO_CACHE_CD__
endif
ifeq ($(NEED_BPP), 16)
FLAGS += -DWANT_16BPP
endif
ifeq ($(NEED_BPP), 32)
FLAGS += -DWANT_32BPP
endif
CXXFLAGS += $(FLAGS)
CFLAGS += $(FLAGS) -std=gnu99

View File

@ -24,6 +24,7 @@ std::string retro_base_directory;
std::string retro_base_name;
#if defined(WANT_PSX_EMU)
#define MEDNAFEN_CORE_NAME_MODULE "psx"
#define MEDNAFEN_CORE_NAME "Mednafen PSX"
#define MEDNAFEN_CORE_EXTENSIONS "cue|CUE|toc|TOC"
#define MEDNAFEN_CORE_TIMING_FPS 59.85398
@ -34,8 +35,19 @@ std::string retro_base_name;
#define MEDNAFEN_CORE_GEOMETRY_ASPECT_RATIO (4.0 / 3.0)
#define FB_WIDTH 680
#define FB_HEIGHT 576
#elif defined(WANT_PCE_FAST_EMU)
#define MEDNAFEN_CORE_NAME_MODULE "pce_fast"
#define MEDNAFEN_CORE_NAME "Mednafen PCE Fast"
#define MEDNAFEN_CORE_EXTENSIONS "pce|PCE|cue|CUE|zip|ZIP"
#define MEDNAFEN_CORE_TIMING_FPS 59.82
#define MEDNAFEN_CORE_GEOMETRY_BASE_W (game->nominal_width)
#define MEDNAFEN_CORE_GEOMETRY_BASE_H (game->nominal_height)
#define MEDNAFEN_CORE_GEOMETRY_MAX_W 512
#define MEDNAFEN_CORE_GEOMETRY_MAX_H 242
#define MEDNAFEN_CORE_GEOMETRY_ASPECT_RATIO (4.0 / 3.0)
#define FB_WIDTH 512
#define FB_HEIGHT 242
#endif
const char *mednafen_core_str = MEDNAFEN_CORE_NAME;
@ -88,9 +100,11 @@ bool retro_load_game(const struct retro_game_info *info)
if (failed_init)
return false;
#ifdef WANT_32BPP
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
rgb32 = true;
#endif
const char *base = strrchr(info->path, '/');
if (!base)
@ -103,7 +117,7 @@ bool retro_load_game(const struct retro_game_info *info)
retro_base_name = retro_base_name.substr(0, retro_base_name.find_last_of('.'));
game = MDFNI_LoadGame("psx", info->path);
game = MDFNI_LoadGame(MEDNAFEN_CORE_NAME_MODULE, info->path);
if (!game)
return false;
@ -127,18 +141,16 @@ void retro_unload_game()
delete [] mednafen_buf;
}
#ifndef __SSE2__
#error "SSE2 required."
#endif
#if defined(WANT_PSX_EMU)
#include <emmintrin.h>
static inline void convert_surface()
{
#ifdef __SSE2__
// PSX core should be able to output ARGB1555 directly,
// so we can avoid this conversion step.
// Done in SSE2 here because any system that can run this
// core to begin with will be at least that powerful (as of writing).
static inline void convert_surface()
{
const uint32_t *pix = surf->pixels;
for (unsigned i = 0; i < (MDFNGameInfo->fb_width * MDFNGameInfo->fb_height); i += 8)
{
@ -165,7 +177,9 @@ static inline void convert_surface()
_mm_store_si128((__m128i*)(conv_buf + i), _mm_packs_epi32(res0, res1));
}
#endif
}
#endif
static unsigned retro_devices[2];
@ -260,6 +274,42 @@ static void update_input(void)
break;
}
}
#elif defined(WANT_PCE_FAST_EMU)
static uint8_t input_buf[5][2];
static unsigned map[] = {
RETRO_DEVICE_ID_JOYPAD_Y,
RETRO_DEVICE_ID_JOYPAD_B,
RETRO_DEVICE_ID_JOYPAD_SELECT,
RETRO_DEVICE_ID_JOYPAD_START,
RETRO_DEVICE_ID_JOYPAD_UP,
RETRO_DEVICE_ID_JOYPAD_RIGHT,
RETRO_DEVICE_ID_JOYPAD_DOWN,
RETRO_DEVICE_ID_JOYPAD_LEFT,
RETRO_DEVICE_ID_JOYPAD_A,
RETRO_DEVICE_ID_JOYPAD_X,
RETRO_DEVICE_ID_JOYPAD_L,
RETRO_DEVICE_ID_JOYPAD_R,
RETRO_DEVICE_ID_JOYPAD_L2
};
if (input_state_cb)
{
for (unsigned j = 0; j < 5; j++)
{
uint16_t input_state = 0;
for (unsigned i = 0; i < 13; i++)
input_state |= input_state_cb(j, RETRO_DEVICE_JOYPAD, 0, map[i]) ? (1 << i) : 0;
// Input data must be little endian.
input_buf[j][0] = (input_state >> 0) & 0xff;
input_buf[j][1] = (input_state >> 8) & 0xff;
}
}
// Possible endian bug ...
for (unsigned i = 0; i < 5; i++)
MDFNI_SetInput(i, "gamepad", &input_buf[i][0], 0);
#endif
}
@ -273,7 +323,9 @@ void retro_run()
static int16_t sound_buf[0x10000];
static MDFN_Rect rects[FB_HEIGHT];
#ifdef WANT_PSX_EMU
rects[0].w = ~0;
#endif
EmulateSpecStruct spec = {0};
spec.surface = surf;
@ -286,9 +338,14 @@ void retro_run()
MDFNI_Emulate(&spec);
#ifdef WANT_PSX_EMU
unsigned width = rects[0].w;
unsigned height = spec.DisplayRect.h;
unsigned int ptrDiff = 0;
#else
unsigned width = rects->w;
unsigned height = rects->h;
#endif
#ifdef WANT_PSX_EMU
// This is for PAL, the core implements PAL over NTSC TV so you get the
@ -334,6 +391,9 @@ void retro_run()
ptr += ptrDiff;
video_cb(ptr, width, height, FB_WIDTH << 1);
}
#elif defined(WANT_PCE_FAST_EMU)
const uint16_t *pix = surf->pixels16;
video_cb(pix, width, height, FB_WIDTH << 1);
#endif
video_frames++;
@ -349,6 +409,7 @@ void retro_get_system_info(struct retro_system_info *info)
info->library_version = "0.9.26";
info->need_fullpath = true;
info->valid_extensions = MEDNAFEN_CORE_EXTENSIONS;
info->block_extract = false;
}
void retro_get_system_av_info(struct retro_system_av_info *info)
@ -394,7 +455,6 @@ void retro_set_controller_port_device(unsigned in_port, unsigned device)
"[%s]: Only the 2 main ports are supported at the moment", mednafen_core_str);
return;
}
#endif
switch (device)
{
@ -409,6 +469,7 @@ void retro_set_controller_port_device(unsigned in_port, unsigned device)
fprintf(stderr,
"[%s]: Unsupported controller device, falling back to gamepad", mednafen_core_str);
}
#endif
}
void retro_set_environment(retro_environment_t cb)
@ -441,6 +502,8 @@ void retro_set_video_refresh(retro_video_refresh_t cb)
video_cb = cb;
}
static size_t serialize_size;
size_t retro_serialize_size(void)
{
return 0;

View File

@ -78,13 +78,13 @@ class MDFNFILE
}
char *fgets(char *s, int size);
private:
uint8 *f_data;
int64 f_size;
char *f_ext;
private:
int error_code;
int local_errno;

330
mednafen/hw_cpu/c68k/c68k.c Normal file
View File

@ -0,0 +1,330 @@
/* Copyright 2003-2004 Stephane Dallongeville
This file is part of Yabause.
Yabause 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.
Yabause 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 Yabause; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*********************************************************************************
*
* C68K (68000 CPU emulator) version 0.80
* Compiled with Dev-C++
* Copyright 2003-2004 Stephane Dallongeville
*
********************************************************************************/
/* Modified heavily for usage in Mednafen:
Made opcode fetches go through the external memory read function.
Added A-line and F-line emulation.
Added packed save state code.
Gutted the timing code.
Scrapped the goto table code.
Redid the C/X flag calculation on some 32-bit instructions.
Other stuff I can't remember.
If you want a more-or-less original version of C68k(which, in its original state, can be quite fast),
check out Yabause's code(though I think my A-line and F-line emulation improvements are in that tree now too).
*/
#include <stdio.h>
#include <string.h>
#include "c68k.h"
// shared global variable
//////////////////////////
c68k_struc C68K;
// include macro file
//////////////////////
#include "c68kmac.inc"
// prototype
/////////////
u8 C68K_FASTCALL C68k_Read8_Dummy(const u32 adr);
u16 C68K_FASTCALL C68k_Read16_Dummy(const u32 adr);
void C68K_FASTCALL C68k_Write8_Dummy(const u32 adr, u8 data);
void C68K_FASTCALL C68k_Write16_Dummy(const u32 adr, u16 data);
static u32 C68k_Read_Long(c68k_struc *cpu, u32 adr);
s32 C68K_FASTCALL C68k_Interrupt_Ack_Dummy(s32 level);
void C68K_FASTCALL C68k_Reset_Dummy(void);
// core main functions
///////////////////////
void C68k_Init(c68k_struc *cpu, C68K_INT_CALLBACK *int_cb)
{
memset(cpu, 0, sizeof(c68k_struc));
C68k_Set_ReadB(cpu, C68k_Read8_Dummy);
C68k_Set_ReadW(cpu, C68k_Read16_Dummy);
C68k_Set_WriteB(cpu, C68k_Write8_Dummy);
C68k_Set_WriteW(cpu, C68k_Write16_Dummy);
C68k_Set_TAS_Hack(cpu, 0);
//C68k_Set_Debug(cpu, NULL);
if (int_cb) cpu->Interrupt_CallBack = int_cb;
else cpu->Interrupt_CallBack = C68k_Interrupt_Ack_Dummy;
cpu->Reset_CallBack = C68k_Reset_Dummy;
}
s32 C68K_FASTCALL C68k_Reset(c68k_struc *cpu)
{
//memset(cpu, 0, (u32)(&(cpu->dirty1)) - (u32)(&(cpu->D[0])));
memset(cpu, 0, ((u8 *)&(cpu->dirty1)) - ((u8 *)&(cpu->D[0])));
cpu->flag_I = 7;
cpu->flag_S = C68K_SR_S;
cpu->A[7] = C68k_Read_Long(cpu, 0);
C68k_Set_PC(cpu, C68k_Read_Long(cpu, 4));
return cpu->Status;
}
void C68k_Set_TAS_Hack(c68k_struc *cpu, int value)
{
cpu->TAS_Hack = value ? 1 : 0;
}
/////////////////////////////////
void C68K_FASTCALL C68k_Set_IRQ(c68k_struc *cpu, s32 level)
{
cpu->IRQLine = level;
//cpu->Status &= ~(C68K_HALTED | C68K_WAITING);
}
// Read / Write dummy functions
////////////////////////////////
u8 C68K_FASTCALL C68k_Read8_Dummy(const u32 adr)
{
return 0;
}
u16 C68K_FASTCALL C68k_Read16_Dummy(const u32 adr)
{
return 0;
}
void C68K_FASTCALL C68k_Write8_Dummy(const u32 adr, u8 data)
{
}
void C68K_FASTCALL C68k_Write16_Dummy(const u32 adr, u16 data)
{
}
s32 C68K_FASTCALL C68k_Interrupt_Ack_Dummy(s32 level)
{
// return vector
return (C68K_INTERRUPT_AUTOVECTOR_EX + level);
}
void C68K_FASTCALL C68k_Reset_Dummy(void)
{
}
// Read / Write core functions
///////////////////////////////
static u32 C68k_Read_Long(c68k_struc *cpu, u32 adr)
{
return (cpu->Read_Word(adr) << 16) | (cpu->Read_Word(adr + 2) & 0xFFFF);
}
// setting core functions
//////////////////////////
void C68k_Set_ReadB(c68k_struc *cpu, C68K_READ8 *Func)
{
cpu->Read_Byte = Func;
}
void C68k_Set_ReadW(c68k_struc *cpu, C68K_READ16 *Func)
{
cpu->Read_Word = Func;
}
void C68k_Set_WriteB(c68k_struc *cpu, C68K_WRITE8 *Func)
{
cpu->Write_Byte = Func;
}
void C68k_Set_WriteW(c68k_struc *cpu, C68K_WRITE16 *Func)
{
cpu->Write_Word = Func;
}
// externals main functions
////////////////////////////
u32 C68k_Get_DReg(c68k_struc *cpu, u32 num)
{
return cpu->D[num];
}
u32 C68k_Get_AReg(c68k_struc *cpu, u32 num)
{
return cpu->A[num];
}
u32 C68k_Get_PC(c68k_struc *cpu)
{
return (cpu->PC);
}
u32 C68k_Get_SR(c68k_struc *cpu)
{
c68k_struc *CPU = cpu;
return GET_SR;
}
u32 C68k_Get_USP(c68k_struc *cpu)
{
if (cpu->flag_S) return cpu->USP;
else return cpu->A[7];
}
u32 C68k_Get_MSP(c68k_struc *cpu)
{
if (cpu->flag_S) return cpu->A[7];
else return cpu->USP;
}
void C68k_Set_DReg(c68k_struc *cpu, u32 num, u32 val)
{
cpu->D[num] = val;
}
void C68k_Set_AReg(c68k_struc *cpu, u32 num, u32 val)
{
cpu->A[num] = val;
}
void C68k_Set_PC(c68k_struc *cpu, u32 val)
{
cpu->PC = val;
}
void C68k_Set_SR(c68k_struc *cpu, u32 val)
{
c68k_struc *CPU = cpu;
SET_SR(val);
}
void C68k_Set_USP(c68k_struc *cpu, u32 val)
{
if (cpu->flag_S) cpu->USP = val;
else cpu->A[7] = val;
}
void C68k_Set_MSP(c68k_struc *cpu, u32 val)
{
if (cpu->flag_S) cpu->A[7] = val;
else cpu->USP = val;
}
unsigned int C68k_Get_State_Max_Len(void)
{
//printf("loopie: %d\n", (int)sizeof(c68k_struc));
return(512);
}
#define PACK_U32(val) { u32 temp = (val); buffer[index++] = temp; buffer[index++] = temp >> 8; buffer[index++] = temp >> 16; buffer[index++] = temp >> 24; }
#define UNPACK_U32(target) { if(index >= length) goto BadBad; target = buffer[index] | (buffer[index + 1] << 8) | (buffer[index + 2] << 16) | (buffer[index + 3] << 24); index += 4; }
void C68k_Save_State(c68k_struc *cpu, u8 *buffer)
{
int index = 0;
int length = C68k_Get_State_Max_Len();
int i;
PACK_U32(0); //0xDEADBEEF);
for(i = 0; i < 16; i++)
{
PACK_U32(cpu->DA[i]);
}
PACK_U32(cpu->flag_C);
PACK_U32(cpu->flag_V);
PACK_U32(cpu->flag_notZ);
PACK_U32(cpu->flag_N);
PACK_U32(cpu->flag_X);
PACK_U32(cpu->flag_I);
PACK_U32(cpu->flag_S);
PACK_U32(cpu->USP);
PACK_U32(cpu->PC);
PACK_U32(cpu->Status);
PACK_U32(cpu->IRQLine);
PACK_U32(0xDEADBEEF);
//printf("Save: %d\n", index);
}
void C68k_Load_State(c68k_struc *cpu, const u8 *buffer)
{
int index = 0;
int length = C68k_Get_State_Max_Len();
int version;
int i;
u32 footer_check;
UNPACK_U32(version);
for(i = 0; i < 16; i++)
{
UNPACK_U32(cpu->DA[i]);
}
UNPACK_U32(cpu->flag_C);
UNPACK_U32(cpu->flag_V);
UNPACK_U32(cpu->flag_notZ);
UNPACK_U32(cpu->flag_N);
UNPACK_U32(cpu->flag_X);
UNPACK_U32(cpu->flag_I);
UNPACK_U32(cpu->flag_S);
UNPACK_U32(cpu->USP);
UNPACK_U32(cpu->PC);
UNPACK_U32(cpu->Status);
UNPACK_U32(cpu->IRQLine);
UNPACK_U32(footer_check);
//printf("%08x\n", footer_check);
//printf("Load: %d\n", index);
return;
BadBad:
puts("Very bad");
return;
}

237
mednafen/hw_cpu/c68k/c68k.h Normal file
View File

@ -0,0 +1,237 @@
/* Copyright 2003-2004 Stephane Dallongeville
Copyright 2004 Theo Berkau
This file is part of Yabause.
Yabause 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.
Yabause 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 Yabause; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*********************************************************************************
* C68K.H :
*
* C68K include file
*
********************************************************************************/
#ifndef _C68K_H_
#define _C68K_H_
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define C68K_FASTCALL
#include <stdint.h>
typedef int64_t s64;
typedef uint64_t u64;
typedef int32_t s32;
typedef uint32_t u32;
typedef int16_t s16;
typedef uint16_t u16;
typedef int8_t s8;
typedef uint8_t u8;
#ifdef __cplusplus
extern "C" {
#endif
// setting
///////////
//#define C68K_GEN
#ifdef MSB_FIRST
#define C68K_BIG_ENDIAN
#endif
#ifdef C68K_BIG_ENDIAN
#define BYTE_OFF 3
#define WORD_OFF 1
#else
#define BYTE_OFF 0
#define WORD_OFF 0
#endif
#define C68K_NO_JUMP_TABLE
//#define C68K_CONST_JUMP_TABLE
//#define C68K_AUTOVECTOR_CALLBACK
// 68K core types definitions
//////////////////////////////
#define C68K_ADR_BITS 24
#define C68K_SR_C_SFT 8
#define C68K_SR_V_SFT 7
#define C68K_SR_Z_SFT 0
#define C68K_SR_N_SFT 7
#define C68K_SR_X_SFT 8
#define C68K_SR_S_SFT 13
#define C68K_SR_C (1 << C68K_SR_C_SFT)
#define C68K_SR_V (1 << C68K_SR_V_SFT)
#define C68K_SR_Z 0
#define C68K_SR_N (1 << C68K_SR_N_SFT)
#define C68K_SR_X (1 << C68K_SR_X_SFT)
#define C68K_SR_S (1 << C68K_SR_S_SFT)
#define C68K_CCR_MASK 0x1F
#define C68K_SR_MASK (0x2700 | C68K_CCR_MASK)
// exception defines taken from musashi core
#define C68K_RESET_EX 1
#define C68K_BUS_ERROR_EX 2
#define C68K_ADDRESS_ERROR_EX 3
#define C68K_ILLEGAL_INSTRUCTION_EX 4
#define C68K_ZERO_DIVIDE_EX 5
#define C68K_CHK_EX 6
#define C68K_TRAPV_EX 7
#define C68K_PRIVILEGE_VIOLATION_EX 8
#define C68K_TRACE_EX 9
#define C68K_1010_EX 10
#define C68K_1111_EX 11
#define C68K_FORMAT_ERROR_EX 14
#define C68K_UNINITIALIZED_INTERRUPT_EX 15
#define C68K_SPURIOUS_INTERRUPT_EX 24
#define C68K_INTERRUPT_AUTOVECTOR_EX 24
#define C68K_TRAP_BASE_EX 32
#define C68K_INT_ACK_AUTOVECTOR -1
#define C68K_HALTED 0x02
#define C68K_WAITING 0x04
#define C68K_DISABLE 0x10
#define C68K_FAULTED 0x40
typedef u8 C68K_FASTCALL C68K_READ8(const u32 adr);
typedef u16 C68K_FASTCALL C68K_READ16(const u32 adr);
typedef void C68K_FASTCALL C68K_WRITE8(const u32 adr, u8 data);
typedef void C68K_FASTCALL C68K_WRITE16(const u32 adr, u16 data);
typedef s32 C68K_FASTCALL C68K_INT_CALLBACK(s32 level);
typedef void C68K_FASTCALL C68K_RESET_CALLBACK(void);
typedef struct
{
union
{
struct
{
u32 D[8]; // 32 bytes aligned
u32 A[8]; // 16 bytes aligned
};
u32 DA[16];
};
u32 flag_C; // 32 bytes aligned
u32 flag_V;
u32 flag_notZ;
u32 flag_N;
u32 flag_X; // 16 bytes aligned
u32 flag_I;
u32 flag_S;
u32 USP;
u32 PC; // 32 bytes aligned
u32 Status;
s32 IRQLine;
s32 timestamp;
u32 dirty1;
C68K_READ8 *Read_Byte; // 32 bytes aligned
C68K_READ16 *Read_Word;
C68K_WRITE8 *Write_Byte;
C68K_WRITE16 *Write_Word;
C68K_INT_CALLBACK *Interrupt_CallBack; // 16 bytes aligned
C68K_RESET_CALLBACK *Reset_CallBack;
int TAS_Hack;
} c68k_struc;
// 68K core var declaration
////////////////////////////
extern c68k_struc C68K;
// 68K core function declaration
/////////////////////////////////
void C68k_Init(c68k_struc *cpu, C68K_INT_CALLBACK *int_cb);
void C68k_Set_TAS_Hack(c68k_struc *cpu, int value);
s32 C68K_FASTCALL C68k_Reset(c68k_struc *cpu);
void C68K_FASTCALL C68k_Exec(c68k_struc *cpu);
void C68K_FASTCALL C68k_Set_IRQ(c68k_struc *cpu, s32 level);
void C68k_Set_ReadB(c68k_struc *cpu, C68K_READ8 *Func);
void C68k_Set_ReadW(c68k_struc *cpu, C68K_READ16 *Func);
void C68k_Set_WriteB(c68k_struc *cpu, C68K_WRITE8 *Func);
void C68k_Set_WriteW(c68k_struc *cpu, C68K_WRITE16 *Func);
void C68k_Set_Debug(c68k_struc *cpu, void (*exec_hook)(u32 address, u16 opcode));
u32 C68k_Get_DReg(c68k_struc *cpu, u32 num);
u32 C68k_Get_AReg(c68k_struc *cpu, u32 num);
u32 C68k_Get_PC(c68k_struc *cpu);
u32 C68k_Get_SR(c68k_struc *cpu);
u32 C68k_Get_USP(c68k_struc *cpu);
u32 C68k_Get_MSP(c68k_struc *cpu);
void C68k_Set_DReg(c68k_struc *cpu, u32 num, u32 val);
void C68k_Set_AReg(c68k_struc *cpu, u32 num, u32 val);
void C68k_Set_PC(c68k_struc *cpu, u32 val);
void C68k_Set_SR(c68k_struc *cpu, u32 val);
void C68k_Set_USP(c68k_struc *cpu, u32 val);
void C68k_Set_MSP(c68k_struc *cpu, u32 val);
#include <string.h>
#ifdef _WIN32
static _inline void C68k_Copy_State(const c68k_struc *source, c68k_struc *dest)
#else
static inline void C68k_Copy_State(const c68k_struc *source, c68k_struc *dest)
#endif
{
memcpy(&dest->D[0], &source->D[0], (&(source->dirty1)) - (&(source->D[0])));
}
unsigned int C68k_Get_State_Max_Len(void);
void C68k_Save_State(c68k_struc *cpu, u8 *buffer);
void C68k_Load_State(c68k_struc *cpu, const u8 *buffer);
#ifdef __cplusplus
}
#endif
#endif // _C68K_H_

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
/* Copyright 2003-2004 Stephane Dallongeville
This file is part of Yabause.
Yabause 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.
Yabause 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 Yabause; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "c68k.h"
// exception cycle table (taken from musashi core)
static const s32 c68k_exception_cycle_table[256] =
{
4, // 0: Reset - Initial Stack Pointer
4, // 1: Reset - Initial Program Counter
50, // 2: Bus Error
50, // 3: Address Error
34, // 4: Illegal Instruction
38, // 5: Divide by Zero
40, // 6: CHK
34, // 7: TRAPV
34, // 8: Privilege Violation
34, // 9: Trace
4, // 10:
4, // 11:
4, // 12: RESERVED
4, // 13: Coprocessor Protocol Violation
4, // 14: Format Error
44, // 15: Uninitialized Interrupt
4, // 16: RESERVED
4, // 17: RESERVED
4, // 18: RESERVED
4, // 19: RESERVED
4, // 20: RESERVED
4, // 21: RESERVED
4, // 22: RESERVED
4, // 23: RESERVED
44, // 24: Spurious Interrupt
44, // 25: Level 1 Interrupt Autovector
44, // 26: Level 2 Interrupt Autovector
44, // 27: Level 3 Interrupt Autovector
44, // 28: Level 4 Interrupt Autovector
44, // 29: Level 5 Interrupt Autovector
44, // 30: Level 6 Interrupt Autovector
44, // 31: Level 7 Interrupt Autovector
34, // 32: TRAP #0
34, // 33: TRAP #1
34, // 34: TRAP #2
34, // 35: TRAP #3
34, // 36: TRAP #4
34, // 37: TRAP #5
34, // 38: TRAP #6
34, // 39: TRAP #7
34, // 40: TRAP #8
34, // 41: TRAP #9
34, // 42: TRAP #10
34, // 43: TRAP #11
34, // 44: TRAP #12
34, // 45: TRAP #13
34, // 46: TRAP #14
34, // 47: TRAP #15
4, // 48: FP Branch or Set on Unknown Condition
4, // 49: FP Inexact Result
4, // 50: FP Divide by Zero
4, // 51: FP Underflow
4, // 52: FP Operand Error
4, // 53: FP Overflow
4, // 54: FP Signaling NAN
4, // 55: FP Unimplemented Data Type
4, // 56: MMU Configuration Error
4, // 57: MMU Illegal Operation Error
4, // 58: MMU Access Level Violation Error
4, // 59: RESERVED
4, // 60: RESERVED
4, // 61: RESERVED
4, // 62: RESERVED
4, // 63: RESERVED
// 64-255: User Defined
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
};
// include macro file
//////////////////////
#include "c68kmac.inc"
// main exec function
//////////////////////
void C68K_FASTCALL C68k_Exec(c68k_struc *cpu)
{
c68k_struc *CPU;
u32 PC;
u32 Opcode;
#ifndef C68K_GEN
#define timestamp cpu->timestamp
CPU = cpu;
PC = CPU->PC;
if (CPU->Status & (C68K_DISABLE | C68K_FAULTED))
{
timestamp += 4; // Close enough >_>
return;
//return (CPU->Status | 0x80000000);
}
CHECK_INT
if (CPU->Status & (C68K_HALTED | C68K_WAITING))
{
timestamp++;
return;
}
Opcode = FETCH_WORD;
PC += 2;
switch(Opcode)
{
#include "c68k_op0.inc"
#include "c68k_op1.inc"
#include "c68k_op2.inc"
#include "c68k_op3.inc"
#include "c68k_op4.inc"
#include "c68k_op5.inc"
#include "c68k_op6.inc"
#include "c68k_op7.inc"
#include "c68k_op8.inc"
#include "c68k_op9.inc"
#include "c68k_opA.inc"
#include "c68k_opB.inc"
#include "c68k_opC.inc"
#include "c68k_opD.inc"
#include "c68k_opE.inc"
#include "c68k_opF.inc"
}
C68k_Exec_End: ;
C68k_Exec_Really_End:
CPU->PC = PC;
return;
#else
return;
#endif
}

View File

@ -0,0 +1,254 @@
/* Copyright 2003-2004 Stephane Dallongeville
This file is part of Yabause.
Yabause 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.
Yabause 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 Yabause; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// internals core macros
/////////////////////////
#define LSL(A, C) ((A) << (C))
#define LSR(A, C) ((A) >> (C))
#define LSR_32(A, C) ((C) < 32 ? (A) >> (C) : 0)
#define LSL_32(A, C) ((C) < 32 ? (A) << (C) : 0)
#define ROL_8(A, C) (LSL(A, C) | LSR(A, 8-(C)))
#define ROL_9(A, C) (LSL(A, C) | LSR(A, 9-(C)))
#define ROL_16(A, C) (LSL(A, C) | LSR(A, 16-(C)))
#define ROL_17(A, C) (LSL(A, C) | LSR(A, 17-(C)))
#define ROL_32(A, C) (LSL_32(A, C) | LSR_32(A, 32-(C)))
#define ROL_33(A, C) (LSL_32(A, C) | LSR_32(A, 33-(C)))
#define ROR_8(A, C) (LSR(A, C) | LSL(A, 8-(C)))
#define ROR_9(A, C) (LSR(A, C) | LSL(A, 9-(C)))
#define ROR_16(A, C) (LSR(A, C) | LSL(A, 16-(C)))
#define ROR_17(A, C) (LSR(A, C) | LSL(A, 17-(C)))
#define ROR_32(A, C) (LSR_32(A, C) | LSL_32(A, 32-(C)))
#define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C)))
#define RET(A) \
timestamp += (A); \
goto C68k_Exec_End;
#define SET_PC(A) PC = (A);
#define READ_BYTE_F(A, D) \
D = CPU->Read_Byte(A) & 0xFF;
#define READ_WORD_F(A, D) \
D = CPU->Read_Word(A) & 0xFFFF;
#define READ_LONG_F(A, D) \
D = CPU->Read_Word((A)) << 16; \
D |= CPU->Read_Word((A) + 2) & 0xFFFF;
#define READSX_BYTE_F(A, D) \
D = (s32)(s8)CPU->Read_Byte(A);
#define READSX_WORD_F(A, D) \
D = (s32)(s16)CPU->Read_Word(A);
#define READSX_LONG_F(A, D) \
D = CPU->Read_Word((A)) << 16; \
D |= CPU->Read_Word((A) + 2) & 0xFFFF;
#define WRITE_BYTE_F(A, D) \
CPU->Write_Byte(A, D);
#define WRITE_WORD_F(A, D) \
CPU->Write_Word(A, D);
#define WRITE_LONG_F(A, D) \
CPU->Write_Word((A), (D) >> 16); \
CPU->Write_Word((A) + 2, (D) & 0xFFFF);
#define WRITE_LONG_DEC_F(A, D) \
CPU->Write_Word((A) + 2, (D) & 0xFFFF); \
CPU->Write_Word((A), (D) >> 16);
#define PUSH_16_F(D) \
CPU->A[7] -= 2; \
CPU->Write_Word(CPU->A[7], D); \
#define POP_16_F(D) \
D = (u16)CPU->Read_Word(CPU->A[7]); \
CPU->A[7] += 2;
#define PUSH_32_F(D) \
CPU->A[7] -= 4; \
CPU->Write_Word(CPU->A[7] + 2, (D) & 0xFFFF); \
CPU->Write_Word(CPU->A[7], (D) >> 16);
#define POP_32_F(D) \
D = CPU->Read_Word(CPU->A[7]) << 16; \
D |= CPU->Read_Word(CPU->A[7] + 2) & 0xFFFF; \
CPU->A[7] += 4;
/* */
/* New timing hacky stuff */
/* */
#define READ_BYat_F(A, D) \
timestamp += 2; \
D = CPU->Read_Byte(A) & 0xFF; \
timestamp += 2;
#define READ_WOat_F(A, D) \
timestamp += 2; \
D = CPU->Read_Word(A) & 0xFFFF; \
timestamp += 2;
#define READ_LOat_F(A, D) \
timestamp += 2; \
D = CPU->Read_Word((A)) << 16; \
timestamp += 2; \
timestamp += 2; \
D |= CPU->Read_Word((A) + 2) & 0xFFFF; \
timestamp += 2;
#define READSX_BYat_F(A, D) \
timestamp += 2; \
D = (s32)(s8)CPU->Read_Byte(A); \
timestamp += 2;
#define READSX_WOat_F(A, D) \
timestamp += 2; \
D = (s32)(s16)CPU->Read_Word(A); \
timestamp += 2;
#define READSX_LOat_F(A, D) \
timestamp += 2; \
D = CPU->Read_Word((A)) << 16; \
timestamp += 2; \
timestamp += 2; \
D |= CPU->Read_Word((A) + 2) & 0xFFFF; \
timestamp += 2;
#define WRITE_BYat_F(A, D) \
timestamp += 2; \
CPU->Write_Byte(A, D); \
timestamp += 2;
#define WRITE_WOat_F(A, D) \
timestamp += 2; \
CPU->Write_Word(A, D); \
timestamp += 2; \
#define WRITE_LOat_F(A, D) \
timestamp += 2; \
CPU->Write_Word((A), (D) >> 16); \
timestamp += 2; \
timestamp += 2; \
CPU->Write_Word((A) + 2, (D) & 0xFFFF); \
timestamp += 2;
#define WRITE_LOat_DEC_F(A, D) \
timestamp += 2; \
CPU->Write_Word((A) + 2, (D) & 0xFFFF); \
timestamp += 2; \
timestamp += 2; \
CPU->Write_Word((A), (D) >> 16); \
timestamp += 2;
/* */
/* */
/* */
#define FETCH_BYTE ((u8)CPU->Read_Word(PC))
#define FETCH_WORD CPU->Read_Word(PC)
#define FETCH_LONG ((CPU->Read_Word(PC) << 16) | (CPU->Read_Word(PC + 2)))
// FIXME?
#define DECODE_EXT_WORD \
{ \
u32 ext; \
\
ext = FETCH_WORD; \
PC += 2; \
\
adr += (s32)((s8)(ext)); \
if (ext & 0x0800) adr += (s32) CPU->D[ext >> 12]; \
else adr += (s32)((s16)(CPU->D[ext >> 12])); \
}
#define GET_CCR \
(((CPU->flag_C >> (C68K_SR_C_SFT - 0)) & 1) | \
((CPU->flag_V >> (C68K_SR_V_SFT - 1)) & 2) | \
(((!CPU->flag_notZ) & 1) << 2) | \
((CPU->flag_N >> (C68K_SR_N_SFT - 3)) & 8) | \
((CPU->flag_X >> (C68K_SR_X_SFT - 4)) & 0x10))
#define GET_SR \
((CPU->flag_S << 0) | \
(CPU->flag_I << 8) | \
GET_CCR)
#define SET_CCR(A) \
CPU->flag_C = (A) << (C68K_SR_C_SFT - 0); \
CPU->flag_V = (A) << (C68K_SR_V_SFT - 1); \
CPU->flag_notZ = ~(A) & 4; \
CPU->flag_N = (A) << (C68K_SR_N_SFT - 3); \
CPU->flag_X = (A) << (C68K_SR_X_SFT - 4);
#define SET_SR(A) \
SET_CCR(A) \
CPU->flag_I = ((A) >> 8) & 7; \
CPU->flag_S = (A) & C68K_SR_S;
#define CHECK_INT \
{ \
s32 line, vect; \
\
line = CPU->IRQLine; \
/*if(line) printf("Meow: %d, flag_I: %d\n", line, CPU->flag_I); */ \
if ((line == 7) || (line > CPU->flag_I)) \
{ \
cpu->Status &= ~(C68K_HALTED | C68K_WAITING); \
\
/* get vector */ \
CPU->IRQLine = 0; \
vect = CPU->Interrupt_CallBack(line); \
if (vect == C68K_INT_ACK_AUTOVECTOR) \
vect = C68K_INTERRUPT_AUTOVECTOR_EX + (line & 7); \
\
/* adjust CCnt */ \
timestamp += c68k_exception_cycle_table[vect]; \
\
/* swap A7 and USP */ \
if (!CPU->flag_S) \
{ \
u32 tmpSP; \
\
tmpSP = CPU->USP; \
CPU->USP = CPU->A[7]; \
CPU->A[7] = tmpSP; \
} \
\
/* push PC and SR */ \
PUSH_32_F(PC) \
PUSH_16_F(GET_SR) \
\
/* adjust SR */ \
CPU->flag_S = C68K_SR_S; \
CPU->flag_I = line; \
\
/* fetch new PC */ \
READ_LONG_F(vect * 4, PC) \
SET_PC(PC) \
} \
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
/* Copyright 2003-2004 Stephane Dallongeville
Copyright 2004 Theo Berkau
This file is part of Yabause.
Yabause 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.
Yabause 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 Yabause; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*********************************************************************************
* GEN68K.H :
*
* C68K generator include file
*
********************************************************************************/
#ifndef _GEN68K_H_
#define _GEN68K_H_
#ifdef __cplusplus
extern "C" {
#endif
// setting
///////////
// structure definition
////////////////////////
typedef struct {
u32 name;
u32 mask;
u32 match;
} c68k_ea_info_struc;
typedef struct __c68k_op_info_struc {
s8 op_name[8 + 1];
u16 op_base;
u16 op_mask;
s8 size_type;
s8 size_sft;
s8 eam_sft;
s8 reg_sft;
s8 eam2_sft;
s8 reg2_sft;
s8 ea_supported[12 + 1];
s8 ea2_supported[12 + 1];
void (*genfunc)();
} c68k_op_info_struc;
#ifdef __cplusplus
}
#endif
#endif // _GEN68K_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,790 @@
/* 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
*/
/* Major organizational differences compared to real HuC6280:
PSG emulation is in a completely separate file and class.
Timer and IRQ read/write handlers are called externally from the main(external) PC Engine I/O page memory handler function, for
speed reasons.
Bus cycle extension on VDC and VCE access is simulated/handled in the main(external) PC Engine I/O page memory handler function, for
speed reasons.
Input port emulation is done externally.
Bugs:
The 21MHz master clock penalty when executing(not explicitly branching) across a 8KiB page boundary is not emulated.
*/
#include "../../mednafen.h"
#include "huc6280.h"
#include <string.h>
#ifdef WANT_DEBUGGER
#include <trio/trio.h>
#endif
//#define IncPC() { PC++; if(!(PC & 0x1FFF)) printf("Crossing: %04x %02x\n", PC - 1, lastop); }
#define LASTCYCLE /*assert(((P & I_FLAG) ? 0 : (uint32)~0) == PIMaskCache);*/ IRQSample = (IRQlow & IRQMask) & PIMaskCache; IFlagSample = P & I_FLAG; ADDCYC(1);
void HuC6280::StealCycle(void)
{
ADDCYC(1);
}
void HuC6280::StealCycles(const int count)
{
ADDCYC(count);
}
void HuC6280::StealMasterCycles(const int count)
{
ADDCYC_MASTER(count);
}
void HuC6280::FlushMPRCache(void)
{
for(int x = 0; x < 9; x++)
SetMPR(x, MPR[x & 0x7]);
}
INLINE void HuC6280::PUSH(const uint8 V)
{
WrMem(0x2100 | S, V);
S--;
}
INLINE uint8 HuC6280::POP(void)
{
S++;
return(RdMem(0x2100 | S));
}
static uint8 ZNTable[256];
/* Some of these operations will only make sense if you know what the flag
constants are. */
INLINE void HuC6280::X_ZN(const uint8 zort)
{
P &= ~(Z_FLAG|N_FLAG);
P |= ZNTable[zort];
}
INLINE void HuC6280::X_ZNT(const uint8 zort)
{
P |= ZNTable[zort];
}
template<bool DebugMode>
INLINE void HuC6280::JR(const bool cond, const bool BBRS)
{
if(cond)
{
int32 disp;
disp=(int8)RdOp(PC);
PC++;
ADDCYC(3);
PC+=disp;
if(DebugMode && ADDBT)
ADDBT(PC - disp - 2 - (BBRS ? 1 : 0), PC, 0);
}
else
{
ADDCYC(1);
PC++;
}
LASTCYCLE;
}
template<bool DebugMode>
INLINE void HuC6280::BBRi(const uint8 val, const unsigned int bitto)
{
JR<DebugMode>(!(val & (1 << bitto)), true);
}
template<bool DebugMode>
INLINE void HuC6280::BBSi(const uint8 val, const unsigned int bitto)
{
JR<DebugMode>(val & (1 << bitto), true);
}
// Total cycles for ST0/ST1/ST2 is effectively 5(4 here, +1 stealcycle in the PC Engine memory handler logic)
#define ST0 { ADDCYC(3); LASTCYCLE; WrMemPhysical(0x80000000 | (0xFF * 8192 + 0), x); }
#define ST1 { ADDCYC(3); LASTCYCLE; WrMemPhysical(0x80000000 | (0xFF * 8192 + 2), x); }
#define ST2 { ADDCYC(3); LASTCYCLE; WrMemPhysical(0x80000000 | (0xFF * 8192 + 3), x); }
#define LDA A=x;X_ZN(A)
#define LDX X=x;X_ZN(X)
#define LDY Y=x;X_ZN(Y)
#define IMP(op) op; break;
#define SAX { uint8 tmp = X; X = A; A = tmp; ADDCYC(2); LASTCYCLE; }
#define SAY { uint8 tmp = Y; Y = A; A = tmp; ADDCYC(2); LASTCYCLE; }
#define SXY { uint8 tmp = X; X = Y; Y = tmp; ADDCYC(2); LASTCYCLE; }
#define TAX { X = A; X_ZN(A); ADDCYC(1); LASTCYCLE; }
#define TXA { A = X; X_ZN(A); ADDCYC(1); LASTCYCLE; }
#define TAY { Y = A; X_ZN(A); ADDCYC(1); LASTCYCLE; }
#define TYA { A = Y; X_ZN(A); ADDCYC(1); LASTCYCLE; }
#define TSX { X = S; X_ZN(X); ADDCYC(1); LASTCYCLE; }
#define TXS { S = X; ADDCYC(1); LASTCYCLE; }
#define DEX { X--; X_ZN(X); ADDCYC(1); LASTCYCLE; }
#define DEY { Y--; X_ZN(Y); ADDCYC(1); LASTCYCLE; }
#define INX { X++; X_ZN(X); ADDCYC(1); LASTCYCLE; }
#define INY { Y++; X_ZN(Y); ADDCYC(1); LASTCYCLE; }
// Combined cycle total of TPREFIX and TPOSTFIX must be 3.
// WARNING: LASTCYCLE is called twice in instructions that make use TPREFIX/TPOSTFIX, so allow for that in the LASTCYCLE
// macro!
#define TPREFIX { uint8 Abackup = A; if(P & T_FLAG) { ADDCYC(1); A = RdMem(0x2000 + X); }
#define TPOSTFIX if(P & T_FLAG) { ADDCYC(1); WrMem(0x2000 + X, A); LASTCYCLE; A = Abackup; } }
/* All of the freaky arithmetic operations. */
#define AND TPREFIX; A&=x;X_ZN(A); TPOSTFIX;
#define BIT P &= ~(Z_FLAG|V_FLAG|N_FLAG); P|=ZNTable[x&A]&Z_FLAG; P|=x&(V_FLAG|N_FLAG);
#define EOR TPREFIX; A^=x;X_ZN(A); TPOSTFIX;
#define ORA TPREFIX; A|=x;X_ZN(A); TPOSTFIX;
// ADC and SBC in decimal mode take 1 extra CPU cycle...we'll add it by using "LASTCYCLE". So now that makes
// LASTCYCLE being called at most 3 times. Not very LASTy, is it!!
#define ADC TPREFIX; { \
if(P & D_FLAG) \
{ \
uint32 low = (A & 0x0F) + (x & 0x0F) + (P & 1); \
uint32 high = (A & 0xF0) + (x & 0xF0); \
P &= ~(Z_FLAG | C_FLAG | N_FLAG); \
if(low > 0x09) { high += 0x10; low += 0x06; } \
if(high > 0x90) { high += 0x60; } \
P |= (high >> 8) & C_FLAG; \
A = (low & 0x0F) | (high & 0xF0); \
X_ZNT(A); \
LASTCYCLE; \
} \
else \
{ \
uint32 l=A+x+(P&1); \
P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
P|=((((A^x)&0x80)^0x80) & ((A^l)&0x80))>>1; \
P|=(l>>8)&C_FLAG; \
A=l; \
X_ZNT(A); \
} \
} TPOSTFIX;
#define SBC if(P & T_FLAG) {puts("SET misuse"); } if(P & D_FLAG) \
{ \
uint32 c = (P & 1) ^ 1; \
uint32 l = A - x - c; \
uint32 low = (A & 0x0f) - (x & 0x0f) - c; \
uint32 high = (A & 0xf0) - (x & 0xf0); \
P &= ~(Z_FLAG | C_FLAG | N_FLAG); \
if(low & 0xf0) low -= 0x06; \
if(low & 0x80) high -= 0x10; \
if(high & 0x0f00) high -= 0x60; \
P |= ((l >> 8) & C_FLAG) ^ C_FLAG; \
A = (low & 0x0F) | (high & 0xf0); \
X_ZNT(A); \
LASTCYCLE; \
} else { \
uint32 l=A-x-((P&1)^1); \
P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
P|=((A^l)&(A^x)&0x80)>>1; \
P|=((l>>8)&C_FLAG)^C_FLAG; \
A=l; \
X_ZNT(A); \
}
#define CMPL(a1,a2) { \
uint32 t=a1-a2; \
X_ZN(t&0xFF); \
P&=~C_FLAG; \
P|=((t>>8)&C_FLAG)^C_FLAG; \
}
#define TAM for(int i = 0; i < 8; i ++) { \
if(x & (1 << i)) \
{ \
SetMPR(i, A); \
} \
} SetMPR(8, MPR[0]); \
ADDCYC(4); \
LASTCYCLE;
#define TMA for(int i = 0; i < 8; i ++) { \
if(x & (1 << i)) \
A = MPR[i]; \
} \
ADDCYC(3); \
LASTCYCLE;
// Note: CSL/CSH's speed timing changes take effect for the last CPU cycle of CSL/CSH. Be cautious
// not to change the order here:
#define CSL { /*printf("CSL: %04x\n", PC);*/ ADDCYC(2); speed = 0; REDOSPEEDCACHE(); LASTCYCLE; }
#define CSH { /*printf("CSH: %04x\n", PC);*/ ADDCYC(2); speed = 1; REDOSPEEDCACHE(); LASTCYCLE; }
#define RMB(bitto) x &= ~(1 << (bitto & 7))
#define SMB(bitto) x |= 1 << (bitto & 7)
#define TSB { P &= ~(Z_FLAG | V_FLAG | N_FLAG); P |= (x | A) ? 0 : Z_FLAG; P |= x & (N_FLAG | V_FLAG); x |= A; }
#define TRB { P &= ~(Z_FLAG | V_FLAG | N_FLAG); P |= (x & ~A) ? 0 : Z_FLAG; P |= x & (N_FLAG | V_FLAG); x &= ~A; }
#define TST { P &= ~(Z_FLAG | V_FLAG | N_FLAG); P |= (x & zoomhack) ? 0: Z_FLAG; P |= x & (V_FLAG | N_FLAG); }
#define CMP CMPL(A,x)
#define CPX CMPL(X,x)
#define CPY CMPL(Y,x)
/* The following operations modify the byte being worked on. */
#define DEC x--;X_ZN(x)
#define INC x++;X_ZN(x)
#define ASL P&=~C_FLAG;P|=x>>7;x<<=1;X_ZN(x)
#define LSR P&=~(C_FLAG|N_FLAG|Z_FLAG);P|=x&1;x>>=1;X_ZNT(x)
#define ROL { \
uint8 l=x>>7; \
x<<=1; \
x|=P&C_FLAG; \
P&=~(Z_FLAG|N_FLAG|C_FLAG); \
P|=l; \
X_ZNT(x); \
}
#define ROR { \
uint8 l=x&1; \
x>>=1; \
x|=(P&C_FLAG)<<7; \
P&=~(Z_FLAG|N_FLAG|C_FLAG); \
P|=l; \
X_ZNT(x); \
}
/* Absolute */
#define GetAB(target) \
{ \
target=RdOp(PC); \
PC++; \
target|=RdOp(PC)<<8; \
PC++; \
}
/* Absolute Indexed(for reads) */
#define GetABI(target, i) \
{ \
unsigned int tmp; \
GetAB(tmp); \
target=tmp; \
target+=i; \
}
/* Zero Page */
#define GetZP(target) \
{ \
target=0x2000 | RdOp(PC); \
PC++; \
}
/* Zero Page Indexed */
#define GetZPI(target,i) \
{ \
target=0x2000 | ((i+RdOp(PC)) & 0xFF); \
PC++; \
}
/* Indirect */
#define GetIND(target) \
{ \
uint8 tmp; \
tmp=RdOp(PC); \
PC++; \
target=RdMem(0x2000 + tmp); \
tmp++; \
target|=RdMem(0x2000 + tmp)<<8; \
}
/* Indexed Indirect */
#define GetIX(target) \
{ \
uint8 tmp; \
tmp=RdOp(PC); \
PC++; \
tmp+=X; \
target=RdMem(0x2000 + tmp); \
tmp++; \
target|=RdMem(0x2000 + tmp) <<8; \
}
/* Indirect Indexed(for reads) */
#define GetIY(target) \
{ \
unsigned int rt; \
uint8 tmp; \
tmp=RdOp(PC); \
rt=RdMem(0x2000 + tmp); \
tmp++; \
rt|=RdMem(0x2000 + tmp)<<8; \
target = (rt + Y); \
PC++; \
}
/* Now come the macros to wrap up all of the above stuff addressing mode functions
and operation macros. Note that operation macros will always operate(redundant
redundant) on the variable "x".
*/
#define RMW_A(op) { uint8 x = A; op; A = x; ADDCYC(1); LASTCYCLE; break; } /* Meh... */
#define RMW_AB(op) { unsigned int EA; uint8 x; GetAB(EA); ADDCYC(6); x=RdMem(EA); op; LASTCYCLE; WrMem(EA,x); break; }
#define RMW_ABI(reg,op) { unsigned int EA; uint8 x; GetABI(EA,reg); ADDCYC(6); x=RdMem(EA); op; LASTCYCLE; WrMem(EA,x); break; }
#define RMW_ABX(op) RMW_ABI(X,op)
#define RMW_ABY(op) RMW_ABI(Y,op)
#define RMW_ZP(op) { unsigned int EA; uint8 x; GetZP(EA); ADDCYC(5); x=RdMem(EA); op; LASTCYCLE; WrMem(EA,x); break; }
#define RMW_ZPX(op) { unsigned int EA; uint8 x; GetZPI(EA, X); ADDCYC(5); x=RdMem(EA); op; LASTCYCLE; WrMem(EA,x); break;}
// For RMB/SMB...
#define RMW_ZP_B(op) { unsigned int EA; uint8 x; GetZP(EA); ADDCYC(5); x=RdMem(EA); ADDCYC(1); op; LASTCYCLE; WrMem(EA,x); break; }
// A LD_IM for complex immediate instructions that take care of cycle consumption in their operation(TAM, TMA, ST0, ST1, ST2)
#define LD_IM_COMPLEX(op) { uint8 x = RdOp(PC); PC++; op; break; }
#define LD_IM(op) {uint8 x; x=RdOp(PC); PC++; ADDCYC(1); LASTCYCLE; op; break;}
#define LD_ZP(op) {unsigned int EA; uint8 x; GetZP(EA); ADDCYC(3); LASTCYCLE; x=RdMem(EA); op; break;}
#define LD_ZPX(op) {unsigned int EA; uint8 x; GetZPI(EA, X); ADDCYC(3); LASTCYCLE; x=RdMem(EA); op; break;}
#define LD_ZPY(op) {unsigned int EA; uint8 x; GetZPI(EA, Y); ADDCYC(3); LASTCYCLE; x=RdMem(EA); op; break;}
#define LD_AB(op) {unsigned int EA; uint8 x; GetAB(EA); ADDCYC(4); LASTCYCLE; x=RdMem(EA); op; break; }
#define LD_ABI(reg,op) {unsigned int EA; uint8 x; GetABI(EA,reg); ADDCYC(4); LASTCYCLE; x=RdMem(EA); op; break;}
#define LD_ABX(op) LD_ABI(X, op)
#define LD_ABY(op) LD_ABI(Y, op)
#define LD_IND(op) {unsigned int EA; uint8 x; GetIND(EA); ADDCYC(6); LASTCYCLE; x=RdMem(EA); op; break;}
#define LD_IX(op) {unsigned int EA; uint8 x; GetIX(EA); ADDCYC(6); LASTCYCLE; x=RdMem(EA); op; break;}
#define LD_IY(op) {unsigned int EA; uint8 x; GetIY(EA); ADDCYC(6); LASTCYCLE; x=RdMem(EA); op; break;}
// For the funky TST instruction
#define LD_IM_TST(op, lt) { uint8 lt = RdOp(PC); PC++; ADDCYC(3); op; }
#define LD_IM_ZP(op) LD_IM_TST(LD_ZP(TST), zoomhack);
#define LD_IM_ZPX(op) LD_IM_TST(LD_ZPX(TST), zoomhack);
#define LD_IM_AB(op) LD_IM_TST(LD_AB(TST), zoomhack);
#define LD_IM_ABX(op) LD_IM_TST(LD_ABX(TST), zoomhack);
#define BMT_PREFIX(pork) in_block_move = IBM_##pork;
#define BMT_LOOPCHECK(pork) if(!runrunrun) { TimerSync(); return; } continue_the_##pork:
#define BMT_TDD BMT_PREFIX(TDD); do { ADDCYC(6); WrMem(bmt_dest, RdMem(bmt_src)); bmt_src--; bmt_dest--; BMT_LOOPCHECK(TDD); bmt_length--; } while(bmt_length);
#define BMT_TAI BMT_PREFIX(TAI); {bmt_alternate = 0; do { ADDCYC(6); WrMem(bmt_dest, RdMem(bmt_src + bmt_alternate)); bmt_dest++; bmt_alternate ^= 1; BMT_LOOPCHECK(TAI); bmt_length--; } while(bmt_length); }
#define BMT_TIA BMT_PREFIX(TIA); {bmt_alternate = 0; do { ADDCYC(6); WrMem(bmt_dest + bmt_alternate, RdMem(bmt_src)); bmt_src++; bmt_alternate ^= 1; BMT_LOOPCHECK(TIA); bmt_length--; } while(bmt_length); }
#define BMT_TII BMT_PREFIX(TII); do { ADDCYC(6); WrMem(bmt_dest, RdMem(bmt_src)); bmt_src++; bmt_dest++; BMT_LOOPCHECK(TII); bmt_length--; } while(bmt_length);
#define BMT_TIN BMT_PREFIX(TIN); do { ADDCYC(6); WrMem(bmt_dest, RdMem(bmt_src)); bmt_src++; BMT_LOOPCHECK(TIN); bmt_length--; } while(bmt_length);
// Block memory transfer load
#define LD_BMT(op) { PUSH(Y); PUSH(A); PUSH(X); GetAB(bmt_src); GetAB(bmt_dest); GetAB(bmt_length); ADDCYC(14); op; in_block_move = 0; X = POP(); A = POP(); Y = POP(); ADDCYC(2); LASTCYCLE; break; }
#define ST_ZP(r) {unsigned int EA; GetZP(EA); ADDCYC(3); LASTCYCLE; WrMem(EA, r); break;}
#define ST_ZPX(r) {unsigned int EA; GetZPI(EA,X); ADDCYC(3); LASTCYCLE; WrMem(EA, r); break;}
#define ST_ZPY(r) {unsigned int EA; GetZPI(EA,Y); ADDCYC(3); LASTCYCLE; WrMem(EA, r); break;}
#define ST_AB(r) {unsigned int EA; GetAB(EA); ADDCYC(4); LASTCYCLE; WrMem(EA, r); break;}
#define ST_ABI(reg,r) {unsigned int EA; GetABI(EA,reg); ADDCYC(4); LASTCYCLE; WrMem(EA,r); break; }
#define ST_ABX(r) ST_ABI(X, r)
#define ST_ABY(r) ST_ABI(Y, r)
#define ST_IND(r) {unsigned int EA; GetIND(EA); ADDCYC(6); LASTCYCLE; WrMem(EA,r); break; }
#define ST_IX(r) {unsigned int EA; GetIX(EA); ADDCYC(6); LASTCYCLE; WrMem(EA,r); break; }
#define ST_IY(r) {unsigned int EA; GetIY(EA); ADDCYC(6); LASTCYCLE; WrMem(EA,r); break; }
void HuC6280::Reset(void)
{
timer_inreload = FALSE;
timer_div = 1024;
timer_load = 0;
timer_value = 0;
timer_status = 0;
in_block_move = 0;
IRQSample = IQRESET;
IRQlow = IQRESET;
}
HuC6280::HuC6280(const bool emulate_wai) : EmulateWAI(emulate_wai)
{
timestamp = 0;
next_user_event = 0;
next_event = 0;
timer_lastts = 0;
timer_inreload = 0;
timer_status = 0;
timer_value = 0;
timer_load = 0;
timer_div = 0;
in_block_move = 0;
isopread = 0;
LastLogicalReadAddr = 0;
LastLogicalWriteAddr = 0;
for(int x = 0; x < 256; x++)
{
if(!x)
ZNTable[x] = Z_FLAG;
else if (x&0x80)
ZNTable[x]=N_FLAG;
else
ZNTable[x]=0;
}
SetCPUHook(NULL, NULL);
}
HuC6280::~HuC6280()
{
}
void HuC6280::Power(void)
{
IODataBuffer = 0xFF;
IRQlow = 0;
PC = 0;
A = 0;
X = 0;
Y = 0;
S = 0;
P = 0;
REDOPIMCACHE();
for(int i = 0; i < 9; i++)
{
MPR[i] = 0;
FastPageR[i] = NULL;
}
Reset();
}
// TimerSync() doesn't call CalcNextEvent(), so we'll need to call it some time after TimerSync() (TimerSync() is
// used in HappySync(), TimerRead(), and TimerWrite().
void HuC6280::TimerSync(void)
{
int32 clocks = timestamp - timer_lastts;
timer_div -= clocks;
while(timer_div <= 0)
{
int32 reload_div = 1024 * 3;
if(timer_inreload)
{
timer_value = timer_load;
reload_div = reload_div - 1; //1023;
timer_inreload = FALSE;
}
else
{
if(timer_status)
{
timer_value --;
if(timer_value < 0)
{
timer_inreload = TRUE;
reload_div = 1;
IRQBegin(IQTIMER);
}
}
}
timer_div += reload_div;
}
timer_lastts = timestamp;
}
void HuC6280::HappySync(void)
{
TimerSync();
if(next_user_event <= 0)
next_user_event = EventHandler->Sync(timestamp);
CalcNextEvent();
}
template<bool DebugMode>
void HuC6280::RunSub(void)
{
uint32 old_PC;
if(DebugMode)
old_PC = PC;
if(in_block_move)
{
switch(in_block_move)
{
default: exit(1);
case IBM_TIA: goto continue_the_TIA;
case IBM_TAI: goto continue_the_TAI;
case IBM_TDD: goto continue_the_TDD;
case IBM_TII: goto continue_the_TII;
case IBM_TIN: goto continue_the_TIN;
}
}
do
{
if(DebugMode)
old_PC = PC;
#include "huc6280_step.inc"
} while(runrunrun > 0);
}
void HuC6280::Run(bool StepMode)
{
if(StepMode)
runrunrun = -1; // Needed so a BMT isn't interrupted.
else
runrunrun = 1;
if(CPUHook || ADDBT)
RunSub<true>();
else
RunSub<false>();
}
uint8 HuC6280::TimerRead(unsigned int address, bool peek)
{
if(!peek)
{
TimerSync();
CalcNextEvent();
}
return(timer_value | (IODataBuffer & 0x80));
}
void HuC6280::TimerWrite(unsigned int address, uint8 V)
{
TimerSync();
switch(address & 1)
{
case 0: timer_load = (V & 0x7F); break;
case 1: if(V & 1) // Enable counter
{
if(timer_status == 0)
{
//if(timer_inreload)
// puts("Oops");
timer_div = 1024 * 3;
timer_value = timer_load;
}
}
timer_status = V & 1;
break;
}
CalcNextEvent();
}
uint8 HuC6280::IRQStatusRead(unsigned int address, bool peek)
{
if(!(address & 2))
return(IODataBuffer);
switch(address & 1)
{
case 0:
if(!peek)
IRQEnd(IQTIMER);
return(IRQMask ^ 0x7);
case 1:
{
int status = 0;
if(IRQlow & IQIRQ1) status |= 2;
if(IRQlow & IQIRQ2) status |= 1;
if(IRQlow & IQTIMER) status |= 4;
return(status | (IODataBuffer & ~(1 | 2 | 4)));
}
}
return(IODataBuffer);
}
void HuC6280::IRQStatusWrite(unsigned int address, uint8 V)
{
if(!(address & 2))
return;
switch(address & 1)
{
case 0: IRQMask = (V & 0x7) ^ 0x7;
break;
case 1: IRQEnd(IQTIMER);
break;
}
}
int HuC6280::StateAction(StateMem *sm, int load, int data_only)
{
uint16 tmp_PC = PC;
SFORMAT StateRegs[]=
{
SFVARN(tmp_PC, "PC"),
SFVARN(A, "A"),
SFVARN(P, "P"),
SFVARN(IFlagSample, "IFlagSample"),
SFVARN(X, "X"),
SFVARN(Y, "Y"),
SFVARN(S, "S"),
SFVARN(lastop, "lastop"),
SFVARN(IRQSample, "IRQSample"),
SFVARN(IRQlow, "IRQlow"),
SFVARN(IRQMask, "IRQMask"),
SFARRAYN(MPR, 8, "MPR"),
SFVARN(speed, "speed"),
SFVARN(timer_inreload, "timer_inreload"),
SFVARN(timer_status, "timer_status"),
SFVARN(timer_value, "timer_value"),
SFVARN(timer_load, "timer_load"),
SFVARN(timer_div, "timer_div"),
SFVARN(in_block_move, "IBM"),
SFVARN(bmt_src, "IBM_SRC"),
SFVARN(bmt_dest, "IBM_DEST"),
SFVARN(bmt_length, "IBM_LENGTH"),
SFVARN(bmt_alternate, "IBM_ALTERNATE"),
SFVARN(timestamp, "timestamp"),
SFVARN(next_event, "next_event"),
SFVARN(next_user_event, "next_user_event"),
// timer_lastts
SFVAR(IODataBuffer),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "CPU");
if(load)
{
PC = tmp_PC;
// Update MPR cache
FlushMPRCache();
REDOSPEEDCACHE();
REDOPIMCACHE();
}
return(ret);
}
void HuC6280::DumpMem(char *filename, uint32 start, uint32 end)
{
FILE *fp=fopen(filename, "wb");
for(uint32 x = start; x <= end; x++)
fputc(RdMem(x), fp);
fclose(fp);
}
void HuC6280::SetRegister(const unsigned int id, uint32 value)
{
switch(id)
{
case GSREG_PC:
PC = value & 0xFFFF;
break;
case GSREG_A:
A = value & 0xFF;
break;
case GSREG_X:
X = value & 0xFF;
break;
case GSREG_Y:
Y = value & 0xFF;
break;
case GSREG_SP:
S = value & 0xFF;
break;
case GSREG_P:
P = value & 0xFF;
REDOPIMCACHE();
break;
case GSREG_SPD:
speed = value & 0x01;
REDOSPEEDCACHE();
break;
case GSREG_MPR0:
case GSREG_MPR1:
case GSREG_MPR2:
case GSREG_MPR3:
case GSREG_MPR4:
case GSREG_MPR5:
case GSREG_MPR6:
case GSREG_MPR7:
MPR[id - GSREG_MPR0] = value & 0xFF;
FlushMPRCache();
break;
case GSREG_IRQM:
IRQMask = (value & 0x7) ^ 0x7;
break;
case GSREG_TIMS:
timer_status = value & 0x1;
break;
case GSREG_TIMV:
timer_value = value & 0x7F;
break;
case GSREG_TIML:
timer_load = value & 0x7F;
break;
case GSREG_TIMD:
timer_div = value & 1023;
break;
}
}

View File

@ -0,0 +1,579 @@
#ifndef __MDFN_HUC6280_H
#define __MDFN_HUC6280_H
#include "../../include/trio/trio.h"
class HuC6280_Support
{
public:
INLINE HuC6280_Support(void)
{
}
INLINE ~HuC6280_Support()
{
}
virtual int32 Sync(const int32 timestamp) = 0;
};
class HuC6280
{
public:
typedef void (*writefunc)(uint32 A, uint8 V);
typedef uint8 (*readfunc)(uint32 A);
enum { N_FLAG = 0x80 };
enum { V_FLAG = 0x40 };
enum { T_FLAG = 0x20 };
enum { B_FLAG = 0x10 };
enum { D_FLAG = 0x08 };
enum { I_FLAG = 0x04 };
enum { Z_FLAG = 0x02 };
enum { C_FLAG = 0x01 };
// If emulate_wai is true, then the "0xCB" opcode will be handled by waiting for the next high-level event, NOT
// for the IRQ line to be asserted as on a 65816.
// It's mainly a hack intended for less CPU-intensive HES playback.
HuC6280(const bool emulate_wai = false);
~HuC6280();
void Reset(void);
void Power(void);
enum { IQIRQ1 = 0x002 };
enum { IQIRQ2 = 0x001 };
enum { IQTIMER = 0x004 };
enum { IQRESET = 0x020 };
INLINE void IRQBegin(int w)
{
IRQlow |= w;
}
INLINE void IRQEnd(int w)
{
IRQlow &= ~w;
}
void TimerSync(void);
INLINE uint8 GetIODataBuffer(void)
{
return(IODataBuffer);
}
INLINE void SetIODataBuffer(uint8 v)
{
IODataBuffer = v;
}
uint8 TimerRead(unsigned int address, bool peek = FALSE);
void TimerWrite(unsigned int address, uint8 V);
uint8 IRQStatusRead(unsigned int address, bool peek = FALSE);
void IRQStatusWrite(unsigned int address, uint8 V);
int StateAction(StateMem *sm, int load, int data_only);
template<bool DebugMode>
void RunSub(void);
void Run(bool StepMode = FALSE);
INLINE void Exit(void)
{
runrunrun = 0;
}
INLINE void SyncAndResetTimestamp(void)
{
TimerSync();
timer_lastts = 0;
timestamp = 0;
}
INLINE bool InBlockMove(void)
{
return(in_block_move);
}
void StealCycle(void);
void StealCycles(const int count);
void StealMasterCycles(const int count);
NO_INLINE void SetEvent(const int32 cycles)
{
next_user_event = cycles;
CalcNextEvent();
}
INLINE void SetEventHandler(HuC6280_Support *new_EventHandler)
{
EventHandler = new_EventHandler;
}
INLINE uint32 Timestamp(void)
{
return(timestamp);
}
//
// Debugger support methods:
//
INLINE void SetCPUHook(void (*new_CPUHook)(uint32), void (*new_ADDBT)(uint32, uint32, uint32))
{
CPUHook = new_CPUHook;
ADDBT = new_ADDBT;
}
INLINE void LoadShadow(const HuC6280 &state)
{
//EmulateWAI = state.EmulateWAI;
PC = state.PC;
A = state.A;
X = state.X;
Y = state.Y;
S = state.S;
P = state.P;
PIMaskCache = state.PIMaskCache;
MPR[0] = state.MPR[0];
MPR[1] = state.MPR[1];
MPR[2] = state.MPR[2];
MPR[3] = state.MPR[3];
MPR[4] = state.MPR[4];
MPR[5] = state.MPR[5];
MPR[6] = state.MPR[6];
MPR[7] = state.MPR[7];
for(int x = 0; x < 9; x++)
SetMPR(x, MPR[x & 0x7]);
IRQlow = state.IRQlow;
IRQSample = state.IRQSample;
IFlagSample = state.IFlagSample;
speed = state.speed;
speed_shift_cache = state.speed_shift_cache;
timestamp = state.timestamp;
IRQMask = state.IRQMask;
//
//
timer_status = 0;
next_user_event = 0x1FFFFFFF;
next_event = 0x1FFFFFFF;
//IRQlow = 0;
//IRQSample = 0;
//IFlagSample = HuC6280::I_FLAG;
}
enum
{
GSREG_PC = 0,
GSREG_A,
GSREG_X,
GSREG_Y,
GSREG_SP,
GSREG_P,
GSREG_MPR0,
GSREG_MPR1,
GSREG_MPR2,
GSREG_MPR3,
GSREG_MPR4,
GSREG_MPR5,
GSREG_MPR6,
GSREG_MPR7,
GSREG_SPD,
GSREG_IRQM,
GSREG_TIMS,
GSREG_TIMV,
GSREG_TIML,
GSREG_TIMD,
GSREG_STAMP
};
INLINE uint32 GetRegister(const unsigned int id, char *special = NULL, const uint32 special_len = 0)
{
uint32 value = 0xDEADBEEF;
switch(id)
{
case GSREG_PC:
value = PC & 0xFFFF;
break;
case GSREG_A:
value = A;
break;
case GSREG_X:
value = X;
break;
case GSREG_Y:
value = Y;
break;
case GSREG_SP:
value = S;
break;
case GSREG_P:
value = P;
if(special)
{
trio_snprintf(special, special_len, "N: %d, V: %d, T: %d, D: %d, I: %d, Z: %d, C: %d", (int)(bool)(value & N_FLAG),
(int)(bool)(value & V_FLAG),
(int)(bool)(value & T_FLAG),
(int)(bool)(value & D_FLAG),
(int)(bool)(value & I_FLAG),
(int)(bool)(value & Z_FLAG),
(int)(bool)(value & C_FLAG));
}
break;
case GSREG_SPD:
value = speed;
if(special)
{
trio_snprintf(special, special_len, "%s(%s)", speed ? "High" : "Low", speed ? "7.16MHz" : "1.79MHz");
}
break;
case GSREG_MPR0:
case GSREG_MPR1:
case GSREG_MPR2:
case GSREG_MPR3:
case GSREG_MPR4:
case GSREG_MPR5:
case GSREG_MPR6:
case GSREG_MPR7:
value = MPR[id - GSREG_MPR0];
if(special)
{
trio_snprintf(special, special_len, "0x%02X * 0x2000 = 0x%06X", value, (uint32)value * 0x2000);
}
break;
case GSREG_IRQM:
value = IRQMask ^ 0x7;
if(special)
{
trio_snprintf(special, special_len, "IRQ2: %s, IRQ1: %s, Timer: %s", (value & IQIRQ2) ? "Disabled" : "Enabled",
(value & IQIRQ1) ? "Disabled" : "Enabled", (value & IQTIMER) ? "Disabled" : "Enabled");
}
break;
case GSREG_TIMS:
value = timer_status;
if(special)
{
trio_snprintf(special, special_len, "%s", (value & 1) ? "Enabled" : "Disabled");
}
break;
case GSREG_TIMV:
value = timer_value;
break;
case GSREG_TIML:
value = timer_load;
if(special)
{
uint32 meowval = (value + 1) * 1024;
trio_snprintf(special, special_len, "(%d + 1) * 1024 = %d; 7,159,090.90... Hz / %d = %f Hz", value, meowval, meowval, (double)7159090.909090909091 / meowval);
}
break;
case GSREG_TIMD:
value = timer_div;
break;
case GSREG_STAMP:
value = timestamp;
break;
}
return(value);
}
//uint32 GetRegister(const unsigned int id, char *special = NULL, const uint32 special_len = 0);
void SetRegister(const unsigned int id, uint32 value);
INLINE void PokePhysical(uint32 address, uint8 data, bool hl = FALSE)
{
address &= 0x1FFFFF;
if(hl)
{
// FIXME: This is a very evil hack.
if(FastMap[address >> 13])
FastMap[address >> 13][address] = data;
}
else
WriteMap[address >> 13](address, data);
}
INLINE void PokeLogical(uint16 address, uint8 data, bool hl = FALSE)
{
uint8 wmpr = MPR[address >> 13];
PokePhysical((wmpr << 13) | (address & 0x1FFF), data, hl);
}
INLINE uint8 PeekPhysical(uint32 address)
{
address &= 0x1FFFFF;
return(ReadMap[address >> 13](address));
}
INLINE uint8 PeekLogical(uint16 address)
{
uint8 wmpr = MPR[address >> 13];
return(PeekPhysical((wmpr << 13) | (address & 0x1FFF)));
}
void DumpMem(char *filename, uint32 start, uint32 end); // For debugging
//
// End Debugger Support Methods
//
INLINE void SetFastRead(unsigned int i, uint8 *ptr)
{
assert(i < 0x100);
FastMap[i] = ptr ? (ptr - i * 8192) : NULL;
}
INLINE readfunc GetReadHandler(unsigned int i)
{
assert(i < 0x100);
return(ReadMap[i]);
}
INLINE void SetReadHandler(unsigned int i, readfunc func)
{
assert(i < 0x100);
ReadMap[i] = func;
}
INLINE void SetWriteHandler(unsigned int i, writefunc func)
{
assert(i < 0x100);
WriteMap[i] = func;
}
// If external debugging code uses this function, then SetFastRead() must not be used with a pointer other than NULL for it to work
// properly.
INLINE uint32 GetLastLogicalReadAddr(void)
{
return(LastLogicalReadAddr);
}
INLINE uint32 GetLastLogicalWriteAddr(void)
{
return(LastLogicalWriteAddr);
}
private:
void FlushMPRCache(void);
INLINE void SetMPR(int i, int v)
{
MPR[i] = v;
FastPageR[i] = FastMap[v] ? (FastMap[v] + v * 8192) - i * 8192 : NULL;
}
// Logical
INLINE uint8 RdMem(unsigned int address)
{
if(FastPageR[address >> 13])
return(FastPageR[address >> 13][address]);
LastLogicalReadAddr = address;
uint8 wmpr = MPR[address >> 13];
return(ReadMap[wmpr]((wmpr << 13) | (address & 0x1FFF)));
}
// Logical(warning: sets/clears isopread)
INLINE uint8 RdOp(unsigned int address)
{
if(FastPageR[address >> 13])
return(FastPageR[address >> 13][address]);
LastLogicalReadAddr = address;
isopread = 1;
uint8 wmpr = MPR[address >> 13];
uint8 ret = ReadMap[wmpr]((wmpr << 13) | (address & 0x1FFF));
isopread = 0;
return(ret);
}
// Logical
INLINE void WrMem(unsigned int address, uint8 V)
{
uint8 wmpr = MPR[address >> 13];
LastLogicalWriteAddr = address;
WriteMap[wmpr]((wmpr << 13) | (address & 0x1FFF), V);
}
// Used for ST0, ST1, ST2
// Must not modify address(upper bit is abused for ST0/ST1/ST2 handling).
INLINE void WrMemPhysical(uint32 address, uint8 data)
{
WriteMap[(address >> 13) & 0xFF](address, data);
}
INLINE void REDOPIMCACHE(void)
{
PIMaskCache = (P & I_FLAG) ? 0 : ~0;
}
INLINE void REDOSPEEDCACHE(void)
{
speed_shift_cache = (speed ^ 1) << 1;
}
INLINE void ADDCYC(int x)
{
int master = (x * 3) << speed_shift_cache;
timestamp += master;
next_event -= master;
next_user_event -= master;
if(next_event <= 0)
HappySync();
}
INLINE void ADDCYC_MASTER(int master)
{
timestamp += master;
next_event -= master;
next_user_event -= master;
if(next_event <= 0)
HappySync();
}
void HappySync(void);
INLINE void CalcNextEvent(void)
{
next_event = timer_div;
if(next_event > next_user_event)
next_event = next_user_event;
}
void X_ZN(const uint8);
void X_ZNT(const uint8);
void PUSH(const uint8 V);
uint8 POP(void);
template<bool DebugMode>
void JR(const bool cond, const bool BBRS = false);
template<bool DebugMode>
void BBRi(const uint8 val, const unsigned int bitto);
template<bool DebugMode>
void BBSi(const uint8 val, const unsigned int bitto);
private:
int runrunrun;
uint32 timestamp;
uint32 PC; // Program Counter(16-bit, but as a 32-bit variable for performance reasons)
uint8 A; // Accumulator
uint8 X; // X Index register
uint8 Y; // Y Indes register
uint8 S; // Stack Pointer
uint8 P; // Processor Flags/Status Register
uint32 PIMaskCache; // Will be = 0 if (P & I_FLAG) is set, ~0 if (P & I_FLAG) is clear.
uint8 MPR[9]; // 8, + 1 for PC overflow from $ffff to $10000
uint8 *FastPageR[9]; // Fast page read cache for each 8KiB in the 16-bit logical address space
// (Reloaded on corresponding MPR change)
int32 next_event; // Next event, period. Timer, user, ALIENS ARE INVADING SAVE ME HELP
int32 next_user_event;
int32 timer_lastts;
uint8 IRQMask;
uint32 LastLogicalReadAddr; // Some helper variables for debugging code(external)
uint32 LastLogicalWriteAddr; // to know where the read/write occurred in the 16-bit logical space.
uint8 lastop;
uint32 IRQlow; /* Simulated IRQ pin held low(or is it high?).
And other junk hooked on for speed reasons.*/
int32 IRQSample;
int32 IFlagSample;
uint8 speed;
uint8 speed_shift_cache;
bool timer_inreload;
uint8 timer_status;
int32 timer_value, timer_load;
int32 timer_div;
uint8 IODataBuffer;
enum
{
IBM_TIA = 1,
IBM_TAI = 2,
IBM_TDD = 3,
IBM_TII = 4,
IBM_TIN = 5
};
uint32 in_block_move;
uint16 bmt_src, bmt_dest, bmt_length;
uint32 bmt_alternate;
bool isopread;
void (*CPUHook)(uint32);
void (*ADDBT)(uint32, uint32, uint32);
HuC6280_Support *EventHandler;
uint8 *FastMap[0x100]; // Direct pointers to memory for mapped RAM and ROM for faster reads(biased to remove the need for an & operation).
readfunc ReadMap[0x100]; // Read handler pointers for each 8KiB in the 21-bit physical address space.
writefunc WriteMap[0x100]; // Write handler pointers for each 8KiB in the 21-bit physical address space.
const bool EmulateWAI; // For speed hacks
};
#endif

View File

@ -0,0 +1,95 @@
if(DebugMode && CPUHook)
{
TimerSync();
CalcNextEvent();
CPUHook(PC);
}
if(IRQSample | IRQlow)
{
if(IRQSample & IQRESET)
{
speed = 0;
REDOSPEEDCACHE();
IRQMask = 7;
SetMPR(7, 0);
PC=RdMem(0xFFFE);
PC|=RdMem(0xFFFF)<<8;
P=I_FLAG;
REDOPIMCACHE();
IRQSample &= ~IQRESET;
IRQlow &= ~IQRESET;
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, 0xFFFE);
continue;
}
else
{
uint32 tmpa = 0;
if((IRQlow & IQTIMER & IRQMask) && !IFlagSample) //IRQSample & IQTIMER)
tmpa = 0xFFFA;
else if(IRQSample & IQIRQ1)
tmpa = 0xFFF8;
else if(IRQSample & IQIRQ2)
tmpa = 0xFFF6;
//else
// puts("DANGER WILL ROBINSON DANGER");
//printf("IRQ: %04x\n", tmpa);
if(tmpa)
{
// Total: 8 cycles(7 ADDCYC(1), 1 LASTCYCLE)
ADDCYC(1); // Cycle 1
RdMem(PC); // Dummy read
ADDCYC(1); // Cycle 2
RdMem(PC + 1); // Dummy read
ADDCYC(1); // Cycle 3
PUSH(PC>>8); // Push PCH
ADDCYC(1); // Cycle 4
PUSH(PC); // Push PCL
ADDCYC(1); // Cycle 5
PUSH((P & ~B_FLAG)); // Push P
P |= I_FLAG;
REDOPIMCACHE();
P &= ~(T_FLAG | D_FLAG);
ADDCYC(1); // Cycle 6
PC=RdMem(tmpa); // Fetch vector PCL
ADDCYC(1); // Cycle 7
PC|=RdMem(tmpa + 1) << 8; // Fect vector PCH
LASTCYCLE; // Cycle 8(internal operation?)
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, tmpa);
continue;
}
}
}
PC &= 0xFFFF; // Our cpu core can only handle PC going about 8192 bytes over, so make sure it never gets that far...
lastop = RdOp(PC);
PC++;
switch(lastop)
{
#include "ops.inc"
}
P &= ~T_FLAG;
skip_T_flag_clear:; // goto'd by the SET code

View File

@ -0,0 +1,554 @@
/* 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
*/
case 0x00: /* BRK */
PC++;
P &= ~T_FLAG;
PUSH(PC >> 8);
PUSH(PC);
PUSH(P | B_FLAG);
P |= I_FLAG;
REDOPIMCACHE();
P &= ~D_FLAG;
PC = RdOp(0xFFF6);
PC |= RdOp(0xFFF7) << 8;
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, 0);
ADDCYC(7);
LASTCYCLE;
break;
case 0x40: /* RTI */
P = POP();
REDOPIMCACHE();
PC = POP();
PC |= POP() << 8;
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, 0);
ADDCYC(6);
LASTCYCLE;
goto skip_T_flag_clear;
break;
case 0x60: /* RTS */
PC = POP();
PC |= POP() << 8;
PC++;
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, 0);
ADDCYC(6);
LASTCYCLE;
break;
case 0x48: /* PHA */
ADDCYC(2);
LASTCYCLE;
PUSH(A);
break;
case 0x08: /* PHP */
ADDCYC(2);
LASTCYCLE;
P &= ~T_FLAG;
PUSH(P | B_FLAG);
break;
case 0xDA: // PHX 65C02
ADDCYC(2);
LASTCYCLE;
PUSH(X);
break;
case 0x5A: // PHY 65C02
ADDCYC(2);
LASTCYCLE;
PUSH(Y);
break;
case 0x68: /* PLA */
ADDCYC(3);
LASTCYCLE;
A = POP();
X_ZN(A);
break;
case 0xFA: // PLX 65C02
ADDCYC(3);
LASTCYCLE;
X = POP();
X_ZN(X);
break;
case 0x7A: // PLY 65C02
ADDCYC(3);
LASTCYCLE;
Y = POP();
X_ZN(Y);
break;
case 0x28: /* PLP */
ADDCYC(3);
LASTCYCLE;
P = POP();
REDOPIMCACHE();
goto skip_T_flag_clear;
break;
case 0x4C: /* JMP ABSOLUTE */
{
uint16 ptmp = PC;
unsigned int npc;
npc = RdOp(ptmp);
ptmp++;
npc |= RdOp(ptmp)<<8;
PC = npc;
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, 0);
ADDCYC(3);
LASTCYCLE;
}
break;
case 0x6C: /* JMP Indirect */
{
uint32 tmp;
GetAB(tmp);
PC = RdMem(tmp);
PC |= RdMem(tmp + 1) << 8;
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, 0);
ADDCYC(6);
LASTCYCLE;
}
break;
case 0x7C: // JMP Indirect X - 65C02
{
uint32 tmp;
GetAB(tmp);
tmp += X;
PC = RdMem(tmp);
PC |= RdMem(tmp + 1) << 8;
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, 0);
ADDCYC(6);
LASTCYCLE;
}
break;
case 0x20: /* JSR */
{
uint8 npc;
npc=RdOp(PC);
PC++;
PUSH(PC >> 8);
PUSH(PC);
PC = RdOp(PC) << 8;
PC |= npc;
if(DebugMode && ADDBT)
ADDBT(old_PC, PC, 0);
ADDCYC(6);
LASTCYCLE;
}
break;
case 0xAA: IMP(TAX);
case 0x8A: IMP(TXA);
case 0xA8: IMP(TAY);
case 0x98: IMP(TYA);
case 0xBA: IMP(TSX);
case 0x9A: IMP(TXS);
case 0xCA: IMP(DEX);
case 0x88: IMP(DEY);
case 0xE8: IMP(INX);
case 0xC8: IMP(INY);
case 0x54: IMP(CSL);
case 0xD4: IMP(CSH);
#define OP_CLEARR(r) { ADDCYC(1); LASTCYCLE; r = 0; break; }
case 0x62: OP_CLEARR(A); // CLA
case 0x82: OP_CLEARR(X); // CLX
case 0xC2: OP_CLEARR(Y); // CLY
case 0x18: /* CLC */
{ ADDCYC(1); LASTCYCLE; P &= ~C_FLAG; break; };
case 0xD8: /* CLD */
{ ADDCYC(1); LASTCYCLE; P &= ~D_FLAG; break; };
case 0x58: /* CLI */
{ ADDCYC(1); LASTCYCLE; P &= ~I_FLAG; REDOPIMCACHE(); break; };
case 0xB8: /* CLV */
{ ADDCYC(1); LASTCYCLE; P &= ~V_FLAG; break; };
case 0x38: /* SEC */
{ ADDCYC(1); LASTCYCLE; P |= C_FLAG; break; };
case 0xF8: /* SED */
{ ADDCYC(1); LASTCYCLE; P |= D_FLAG; break; };
case 0x78: /* SEI */
{ ADDCYC(1); LASTCYCLE; P |= I_FLAG; REDOPIMCACHE(); break; };
case 0xF4: /* SET */
//puts("SET");
ADDCYC(1);
LASTCYCLE;
P |= T_FLAG;
goto skip_T_flag_clear;
break;
case 0xEA: /* NOP */
ADDCYC(1);
LASTCYCLE;
break;
case 0x0A: RMW_A(ASL);
case 0x06: RMW_ZP(ASL);
case 0x16: RMW_ZPX(ASL);
case 0x0E: RMW_AB(ASL);
case 0x1E: RMW_ABX(ASL);
case 0x3A: RMW_A(DEC);
case 0xC6: RMW_ZP(DEC);
case 0xD6: RMW_ZPX(DEC);
case 0xCE: RMW_AB(DEC);
case 0xDE: RMW_ABX(DEC);
case 0x1A: RMW_A(INC); // 65C02
case 0xE6: RMW_ZP(INC);
case 0xF6: RMW_ZPX(INC);
case 0xEE: RMW_AB(INC);
case 0xFE: RMW_ABX(INC);
case 0x4A: RMW_A(LSR);
case 0x46: RMW_ZP(LSR);
case 0x56: RMW_ZPX(LSR);
case 0x4E: RMW_AB(LSR);
case 0x5E: RMW_ABX(LSR);
case 0x2A: RMW_A(ROL);
case 0x26: RMW_ZP(ROL);
case 0x36: RMW_ZPX(ROL);
case 0x2E: RMW_AB(ROL);
case 0x3E: RMW_ABX(ROL);
case 0x6A: RMW_A(ROR);
case 0x66: RMW_ZP(ROR);
case 0x76: RMW_ZPX(ROR);
case 0x6E: RMW_AB(ROR);
case 0x7E: RMW_ABX(ROR);
case 0x69: LD_IM(ADC);
case 0x65: LD_ZP(ADC);
case 0x75: LD_ZPX(ADC);
case 0x6D: LD_AB(ADC);
case 0x7D: LD_ABX(ADC);
case 0x79: LD_ABY(ADC);
case 0x72: LD_IND(ADC);
case 0x61: LD_IX(ADC);
case 0x71: LD_IY(ADC);
case 0x29: LD_IM(AND);
case 0x25: LD_ZP(AND);
case 0x35: LD_ZPX(AND);
case 0x2D: LD_AB(AND);
case 0x3D: LD_ABX(AND);
case 0x39: LD_ABY(AND);
case 0x32: LD_IND(AND);
case 0x21: LD_IX(AND);
case 0x31: LD_IY(AND);
case 0x89: LD_IM(BIT);
case 0x24: LD_ZP(BIT);
case 0x34: LD_ZPX(BIT);
case 0x2C: LD_AB(BIT);
case 0x3C: LD_ABX(BIT);
case 0xC9: LD_IM(CMP);
case 0xC5: LD_ZP(CMP);
case 0xD5: LD_ZPX(CMP);
case 0xCD: LD_AB(CMP);
case 0xDD: LD_ABX(CMP);
case 0xD9: LD_ABY(CMP);
case 0xD2: LD_IND(CMP);
case 0xC1: LD_IX(CMP);
case 0xD1: LD_IY(CMP);
case 0xE0: LD_IM(CPX);
case 0xE4: LD_ZP(CPX);
case 0xEC: LD_AB(CPX);
case 0xC0: LD_IM(CPY);
case 0xC4: LD_ZP(CPY);
case 0xCC: LD_AB(CPY);
case 0x49: LD_IM(EOR);
case 0x45: LD_ZP(EOR);
case 0x55: LD_ZPX(EOR);
case 0x4D: LD_AB(EOR);
case 0x5D: LD_ABX(EOR);
case 0x59: LD_ABY(EOR);
case 0x52: LD_IND(EOR);
case 0x41: LD_IX(EOR);
case 0x51: LD_IY(EOR);
case 0xA9: LD_IM(LDA);
case 0xA5: LD_ZP(LDA);
case 0xB5: LD_ZPX(LDA);
case 0xAD: LD_AB(LDA);
case 0xBD: LD_ABX(LDA);
case 0xB9: LD_ABY(LDA);
case 0xB2: LD_IND(LDA);
case 0xA1: LD_IX(LDA);
case 0xB1: LD_IY(LDA);
case 0xA2: LD_IM(LDX);
case 0xA6: LD_ZP(LDX);
case 0xB6: LD_ZPY(LDX);
case 0xAE: LD_AB(LDX);
case 0xBE: LD_ABY(LDX);
case 0xA0: LD_IM(LDY);
case 0xA4: LD_ZP(LDY);
case 0xB4: LD_ZPX(LDY);
case 0xAC: LD_AB(LDY);
case 0xBC: LD_ABX(LDY);
case 0x09: LD_IM(ORA);
case 0x05: LD_ZP(ORA);
case 0x15: LD_ZPX(ORA);
case 0x0D: LD_AB(ORA);
case 0x1D: LD_ABX(ORA);
case 0x19: LD_ABY(ORA);
case 0x12: LD_IND(ORA);
case 0x01: LD_IX(ORA);
case 0x11: LD_IY(ORA);
case 0xE9: LD_IM(SBC);
case 0xE5: LD_ZP(SBC);
case 0xF5: LD_ZPX(SBC);
case 0xED: LD_AB(SBC);
case 0xFD: LD_ABX(SBC);
case 0xF9: LD_ABY(SBC);
case 0xF2: LD_IND(SBC);
case 0xE1: LD_IX(SBC);
case 0xF1: LD_IY(SBC);
case 0x85: ST_ZP(A);
case 0x95: ST_ZPX(A);
case 0x8D: ST_AB(A);
case 0x9D: ST_ABX(A);
case 0x99: ST_ABY(A);
case 0x92: ST_IND(A);
case 0x81: ST_IX(A);
case 0x91: ST_IY(A);
case 0x86: ST_ZP(X);
case 0x96: ST_ZPY(X);
case 0x8E: ST_AB(X);
case 0x84: ST_ZP(Y);
case 0x94: ST_ZPX(Y);
case 0x8C: ST_AB(Y);
/* BBRi */
case 0x0F: LD_ZP(BBRi<DebugMode>(x, 0));
case 0x1F: LD_ZP(BBRi<DebugMode>(x, 1));
case 0x2F: LD_ZP(BBRi<DebugMode>(x, 2));
case 0x3F: LD_ZP(BBRi<DebugMode>(x, 3));
case 0x4F: LD_ZP(BBRi<DebugMode>(x, 4));
case 0x5F: LD_ZP(BBRi<DebugMode>(x, 5));
case 0x6F: LD_ZP(BBRi<DebugMode>(x, 6));
case 0x7F: LD_ZP(BBRi<DebugMode>(x, 7));
/* BBSi */
case 0x8F: LD_ZP(BBSi<DebugMode>(x, 0));
case 0x9F: LD_ZP(BBSi<DebugMode>(x, 1));
case 0xAF: LD_ZP(BBSi<DebugMode>(x, 2));
case 0xBF: LD_ZP(BBSi<DebugMode>(x, 3));
case 0xCF: LD_ZP(BBSi<DebugMode>(x, 4));
case 0xDF: LD_ZP(BBSi<DebugMode>(x, 5));
case 0xEF: LD_ZP(BBSi<DebugMode>(x, 6));
case 0xFF: LD_ZP(BBSi<DebugMode>(x, 7));
/* BRA */
case 0x80: JR<DebugMode>(1); break;
/* BSR */
case 0x44:
{
PUSH(PC >> 8);
PUSH(PC);
ADDCYC(4);
JR<DebugMode>(1);
}
break;
/* BCC */
case 0x90: JR<DebugMode>(!(P&C_FLAG)); break;
/* BCS */
case 0xB0: JR<DebugMode>(P&C_FLAG); break;
/* BEQ */
case 0xF0: JR<DebugMode>(P&Z_FLAG); break;
/* BNE */
case 0xD0: JR<DebugMode>(!(P&Z_FLAG)); break;
/* BMI */
case 0x30: JR<DebugMode>(P&N_FLAG); break;
/* BPL */
case 0x10: JR<DebugMode>(!(P&N_FLAG)); break;
/* BVC */
case 0x50: JR<DebugMode>(!(P&V_FLAG)); break;
/* BVS */
case 0x70: JR<DebugMode>(P&V_FLAG); break;
// RMB 65SC02
case 0x07: RMW_ZP_B(RMB(0));
case 0x17: RMW_ZP_B(RMB(1));
case 0x27: RMW_ZP_B(RMB(2));
case 0x37: RMW_ZP_B(RMB(3));
case 0x47: RMW_ZP_B(RMB(4));
case 0x57: RMW_ZP_B(RMB(5));
case 0x67: RMW_ZP_B(RMB(6));
case 0x77: RMW_ZP_B(RMB(7));
// SMB 65SC02
case 0x87: RMW_ZP_B(SMB(0));
case 0x97: RMW_ZP_B(SMB(1));
case 0xa7: RMW_ZP_B(SMB(2));
case 0xb7: RMW_ZP_B(SMB(3));
case 0xc7: RMW_ZP_B(SMB(4));
case 0xd7: RMW_ZP_B(SMB(5));
case 0xe7: RMW_ZP_B(SMB(6));
case 0xf7: RMW_ZP_B(SMB(7));
// STZ 65C02
case 0x64: ST_ZP(0);
case 0x74: ST_ZPX(0);
case 0x9C: ST_AB(0);
case 0x9E: ST_ABX(0);
// TRB 65SC02
case 0x14: RMW_ZP(TRB);
case 0x1C: RMW_AB(TRB);
// TSB 65SC02
case 0x04: RMW_ZP(TSB);
case 0x0C: RMW_AB(TSB);
// TST
case 0x83: LD_IM_ZP(TST);
case 0xA3: LD_IM_ZPX(TST);
case 0x93: LD_IM_AB(TST);
case 0xB3: LD_IM_ABX(TST);
case 0x02: IMP(SXY);
case 0x22: IMP(SAX);
case 0x42: IMP(SAY);
case 0x73: // TII
LD_BMT(BMT_TII);
case 0xC3: // TDD
LD_BMT(BMT_TDD);
case 0xD3: // TIN
LD_BMT(BMT_TIN);
case 0xE3: // TIA
LD_BMT(BMT_TIA);
case 0xF3: // TAI
LD_BMT(BMT_TAI);
case 0x43: // TMAi
LD_IM_COMPLEX(TMA);
case 0x53: // TAMi
LD_IM_COMPLEX(TAM);
case 0x03: // ST0
LD_IM_COMPLEX(ST0);
case 0x13: // ST1
LD_IM_COMPLEX(ST1);
case 0x23: // ST2
LD_IM_COMPLEX(ST2);
case 0xCB:
if(EmulateWAI)
{
if(next_event > 1)
ADDCYC(next_event - 1);
LASTCYCLE;
break;
}
default: //MDFN_printf("Bad %02x at $%04x\n", lastop, PC);
ADDCYC(1);
LASTCYCLE;
break;

View File

@ -0,0 +1,8 @@
AUTOMAKE_OPTIONS = subdir-objects
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@ @MATH_OPTIMIZER_FLAGS@
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_builddir)/include/blip -I$(top_srcdir)
noinst_LIBRARIES = libmdfnhwmisc.a
libmdfnhwmisc_a_SOURCES = arcade_card/arcade_card.cpp

View File

@ -0,0 +1,608 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
subdir = src/hw_misc
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cflags_gcc_option.m4 \
$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/fcntl-o.m4 \
$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \
$(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \
$(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \
$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \
$(top_srcdir)/m4/inttypes-pri.m4 \
$(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
$(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \
$(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \
$(top_srcdir)/m4/threadlib.m4 $(top_srcdir)/m4/uintmax_t.m4 \
$(top_srcdir)/m4/visibility.m4 $(top_srcdir)/m4/wchar_t.m4 \
$(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xsize.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/include/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LIBRARIES = $(noinst_LIBRARIES)
ARFLAGS = cru
AM_V_AR = $(am__v_AR_$(V))
am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY))
am__v_AR_0 = @echo " AR " $@;
AM_V_at = $(am__v_at_$(V))
am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
am__v_at_0 = @
libmdfnhwmisc_a_AR = $(AR) $(ARFLAGS)
libmdfnhwmisc_a_LIBADD =
am__dirstamp = $(am__leading_dot)dirstamp
am_libmdfnhwmisc_a_OBJECTS = arcade_card/arcade_card.$(OBJEXT)
libmdfnhwmisc_a_OBJECTS = $(am_libmdfnhwmisc_a_OBJECTS)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
am__v_lt_0 = --silent
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_$(V))
am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY))
am__v_CXX_0 = @echo " CXX " $@;
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_$(V))
am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY))
am__v_CXXLD_0 = @echo " CXXLD " $@;
AM_V_GEN = $(am__v_GEN_$(V))
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(libmdfnhwmisc_a_SOURCES)
DIST_SOURCES = $(libmdfnhwmisc_a_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AM_CFLAGS = @AM_CFLAGS@
AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
CATOBJEXT = @CATOBJEXT@
CC = @CC@
CCAS = @CCAS@
CCASDEPMODE = @CCASDEPMODE@
CCASFLAGS = @CCASFLAGS@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DATADIRNAME = @DATADIRNAME@
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@ @MATH_OPTIMIZER_FLAGS@
DEPDIR = @DEPDIR@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GBA_EXTRA_FLAGS = @GBA_EXTRA_FLAGS@
GENCAT = @GENCAT@
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
GLIBC2 = @GLIBC2@
GLIBC21 = @GLIBC21@
GMSGFMT = @GMSGFMT@
GMSGFMT_015 = @GMSGFMT_015@
GREP = @GREP@
HAVE_ASPRINTF = @HAVE_ASPRINTF@
HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@
HAVE_SNPRINTF = @HAVE_SNPRINTF@
HAVE_VISIBILITY = @HAVE_VISIBILITY@
HAVE_WPRINTF = @HAVE_WPRINTF@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INSTOBJEXT = @INSTOBJEXT@
INTLBISON = @INTLBISON@
INTLLIBS = @INTLLIBS@
INTLOBJS = @INTLOBJS@
INTL_DEFAULT_VERBOSITY = @INTL_DEFAULT_VERBOSITY@
INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
JACK_CFLAGS = @JACK_CFLAGS@
JACK_LIBS = @JACK_LIBS@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCDIO_CFLAGS = @LIBCDIO_CFLAGS@
LIBCDIO_LIBS = @LIBCDIO_LIBS@
LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBMULTITHREAD = @LIBMULTITHREAD@
LIBOBJS = @LIBOBJS@
LIBPTH = @LIBPTH@
LIBPTH_PREFIX = @LIBPTH_PREFIX@
LIBS = @LIBS@
LIBTHREAD = @LIBTHREAD@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBC = @LTLIBC@
LTLIBICONV = @LTLIBICONV@
LTLIBINTL = @LTLIBINTL@
LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
LTLIBOBJS = @LTLIBOBJS@
LTLIBPTH = @LTLIBPTH@
LTLIBTHREAD = @LTLIBTHREAD@
MAKEINFO = @MAKEINFO@
MATH_OPTIMIZER_FLAGS = @MATH_OPTIMIZER_FLAGS@
MKDIR_P = @MKDIR_P@
MMX_CFLAGS = @MMX_CFLAGS@
MSGFMT = @MSGFMT@
MSGFMT_015 = @MSGFMT_015@
MSGMERGE = @MSGMERGE@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POSUB = @POSUB@
PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@
RANLIB = @RANLIB@
SDL_CFLAGS = @SDL_CFLAGS@
SDL_CONFIG = @SDL_CONFIG@
SDL_LIBS = @SDL_LIBS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
SNDFILE_LIBS = @SNDFILE_LIBS@
SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
SSE2_CFLAGS = @SSE2_CFLAGS@
SSE3_CFLAGS = @SSE3_CFLAGS@
SSE_CFLAGS = @SSE_CFLAGS@
STRIP = @STRIP@
TRIO_CFLAGS = @TRIO_CFLAGS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARNING_FLAGS = @WARNING_FLAGS@
WINDRES = @WINDRES@
WOE32 = @WOE32@
WOE32DLL = @WOE32DLL@
XGETTEXT = @XGETTEXT@
XGETTEXT_015 = @XGETTEXT_015@
XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
XMKMF = @XMKMF@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
lt_ECHO = @lt_ECHO@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = subdir-objects
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_builddir)/include/blip -I$(top_srcdir)
noinst_LIBRARIES = libmdfnhwmisc.a
libmdfnhwmisc_a_SOURCES = arcade_card/arcade_card.cpp
all: all-am
.SUFFIXES:
.SUFFIXES: .cpp .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/hw_misc/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/hw_misc/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
arcade_card/$(am__dirstamp):
@$(MKDIR_P) arcade_card
@: > arcade_card/$(am__dirstamp)
arcade_card/$(DEPDIR)/$(am__dirstamp):
@$(MKDIR_P) arcade_card/$(DEPDIR)
@: > arcade_card/$(DEPDIR)/$(am__dirstamp)
arcade_card/arcade_card.$(OBJEXT): arcade_card/$(am__dirstamp) \
arcade_card/$(DEPDIR)/$(am__dirstamp)
libmdfnhwmisc.a: $(libmdfnhwmisc_a_OBJECTS) $(libmdfnhwmisc_a_DEPENDENCIES)
$(AM_V_at)-rm -f libmdfnhwmisc.a
$(AM_V_AR)$(libmdfnhwmisc_a_AR) libmdfnhwmisc.a $(libmdfnhwmisc_a_OBJECTS) $(libmdfnhwmisc_a_LIBADD)
$(AM_V_at)$(RANLIB) libmdfnhwmisc.a
mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f arcade_card/arcade_card.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@arcade_card/$(DEPDIR)/arcade_card.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cpp.lo:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LIBRARIES)
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-rm -f arcade_card/$(DEPDIR)/$(am__dirstamp)
-rm -f arcade_card/$(am__dirstamp)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
mostlyclean-am
distclean: distclean-am
-rm -rf arcade_card/$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf arcade_card/$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
clean-libtool clean-noinstLIBRARIES ctags distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags uninstall uninstall-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,366 @@
/* 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
*/
/*
Arcade Card emulation based on information provided by Ki and David Shadoff
*/
#include "../../mednafen.h"
//#include "pce.h"
//#include "huc.h"
#include "arcade_card.h"
#include <errno.h>
#include <string.h>
static INLINE void ACAutoIncrement(ACPort_t *port)
{
if(port->control & 0x1)
{
if(port->control & 0x10)
{
//if(port->control & 0x4)
//{
// printf("BOONY: %04x\n", port->increment);
// port->base = (port->base + port->increment + 0xFF0000) & 0xFFFFFF;
// printf("%04x\n", port->base);
//}
//else
port->base = (port->base + port->increment) & 0xFFFFFF;
}
else
{
port->offset = (port->offset + port->increment) & 0xFFFF;
}
}
}
uint8 ArcadeCard::Read(uint32 A, bool peek)
{
//printf("AC Read: %04x\n", A);
if((A & 0x1F00) != 0x1A00)
{
//if(!peek)
// printf("AC unknown read: %08x\n", A);
return(0xFF);
}
if(A < 0x1A80)
{
ACPort_t *port = &AC.ports[(A >> 4) & 0x3];
// if(!peek)
// if(A & 0x40)
// printf("AC mirrored port read: %08x\n", A); // Madou Monogatari does!
switch(A & 0xF)
{
case 0x00:
case 0x01:
{
uint32 aci;
uint8 ret;
aci = port->base;
if(port->control & 0x2)
{
aci += port->offset;
if(port->control & 0x8)
aci += 0xFF0000;
}
aci &= 0x1FFFFF;
ret = ACRAM[aci];
if(!peek)
ACAutoIncrement(port);
return(ret);
}
case 0x02: return(port->base >> 0);
case 0x03: return(port->base >> 8);
case 0x04: return(port->base >> 16);
case 0x05: return(port->offset >> 0);
case 0x06: return(port->offset >> 8);
case 0x07: return(port->increment >> 0);
case 0x08: return(port->increment >> 8);
case 0x09: return(port->control);
}
}
else if(A >= 0x1AE0)
{
switch(A & 0x1F)
{
case 0x00:
case 0x01:
case 0x02:
case 0x03: return((AC.shift_latch >> (A & 3) * 8) & 0xFF);
case 0x04: return(AC.shift_bits);
case 0x05: return(AC.rotate_bits);
case 0x1C: return(0x00);
case 0x1D: return(0x00);
case 0x1E: return(0x10); // Version number. We should verify this!
case 0x1F: return(0x51); // Arcade Card ID
}
}
//if(!peek)
// printf("AC unknown read: %08x\n", A);
return(0xFF);
}
void ArcadeCard::Write(uint32 A, uint8 V)
{
//printf("AC Write: %04x %02x\n", A, V);
if((A & 0x1F00) != 0x1A00)
{
//printf("AC unknown write: %08x:%02x\n", A, V);
return;
}
if(A < 0x1A80)
{
ACPort_t *port = &AC.ports[(A >> 4) & 0x3];
switch(A & 0xF)
{
default: //printf("AC unknown write: %08x:%02x\n", A, V);
break;
case 0x00:
case 0x01:
{
uint32 aci;
aci = port->base;
if(port->control & 0x2)
{
aci += port->offset;
if(port->control & 0x8)
aci += 0xFF0000;
}
aci &= 0x1FFFFF;
ACRAMUsed = true;
ACRAM[aci] = V;
ACAutoIncrement(port);
}
break;
case 0x02: port->base &= ~0xFF;
port->base |= V << 0;
break;
case 0x03: port->base &= ~0xFF00;
port->base |= V << 8;
break;
case 0x04: port->base &= ~0xFF0000;
port->base |= V << 16;
break;
case 0x05: port->offset &= ~0xFF;
port->offset |= V << 0;
if((port->control & 0x60) == 0x20)
{
if(port->control & 0x08)
port->base += 0xFF0000;
port->base = (port->base + port->offset) & 0xFFFFFF;
}
break;
case 0x06: port->offset &= ~0xFF00;
port->offset |= V << 8;
if((port->control & 0x60) == 0x40)
{
if(port->control & 0x08)
port->base += 0xFF0000;
port->base = (port->base + port->offset) & 0xFFFFFF;
}
break;
case 0x07: port->increment &= ~0xFF;
port->increment |= V << 0;
break;
case 0x08: port->increment &= ~0xFF00;
port->increment |= V << 8;
break;
case 0x09: port->control = V & 0x7F;
break;
case 0x0A: if((port->control & 0x60) == 0x60)
{
if(port->control & 0x08)
port->base += 0xFF0000;
port->base = (port->base + port->offset) & 0xFFFFFF;
}
break;
}
//if(A & 0x40)
// printf("AC mirrored port write: %08x:%02x\n", A, V);
}
else if(A >= 0x1AE0)
{
switch(A & 0x1F)
{
default: //printf("Unknown AC write: %04x %02x\n", A, V);
break;
case 0x00:
case 0x01:
case 0x02:
case 0x03: AC.shift_latch &= ~(0xFF << (A & 3) * 8);
AC.shift_latch |= (V << (A & 3) * 8);
break;
case 0x04: AC.shift_bits = V & 0xF;
if(AC.shift_bits)
{
if(AC.shift_bits & 0x8)
AC.shift_latch >>= 16 - AC.shift_bits;
else
AC.shift_latch <<= AC.shift_bits;
}
break;
case 0x05: AC.rotate_bits = V & 0xF; // Untested code follows:
if(AC.rotate_bits)
{
if(AC.rotate_bits & 0x8)
{
unsigned int sa = 16 - AC.rotate_bits;
unsigned int orv;
orv = AC.shift_latch << (32 - sa);
AC.shift_latch = (AC.shift_latch >> sa) | orv;
}
else
{
unsigned int sa = AC.rotate_bits;
unsigned int orv;
orv = (AC.shift_latch >> (32 - sa)) & ((1 << sa) - 1);
AC.shift_latch = (AC.shift_latch << sa) | orv;
}
}
break;
}
}
}
ArcadeCard::ArcadeCard(void)
{
ACRAMUsed = false;
memset(&AC, 0, sizeof(AC));
memset(ACRAM, 0, sizeof(ACRAM));
}
ArcadeCard::~ArcadeCard()
{
}
void ArcadeCard::Power(void)
{
memset(ACRAM, 0, 0x200000);
ACRAMUsed = false;
}
int ArcadeCard::StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT ACUsedRegs[] =
{
SFVAR(ACRAMUsed),
SFEND
};
if(!MDFNSS_StateAction(sm, load, data_only, ACUsedRegs, "ArcadeCardUsed"))
return(0);
SFORMAT ACStateRegs[] =
{
SFVARN(AC.ports[0].base, "AC[0].base"), SFVARN(AC.ports[0].offset, "AC[0].offset"),
SFVARN(AC.ports[0].increment, "AC[0].increment"), SFVARN(AC.ports[0].control, "AC[0].control"),
SFVARN(AC.ports[1].base, "AC[1].base"), SFVARN(AC.ports[1].offset, "AC[1].offset"),
SFVARN(AC.ports[1].increment, "AC[1].increment"), SFVARN(AC.ports[1].control, "AC[1].control"),
SFVARN(AC.ports[2].base, "AC[2].base"), SFVARN(AC.ports[2].offset, "AC[2].offset"),
SFVARN(AC.ports[2].increment, "AC[2].increment"), SFVARN(AC.ports[2].control, "AC[2].control"),
SFVARN(AC.ports[3].base, "AC[3].base"), SFVARN(AC.ports[3].offset, "AC[3].offset"),
SFVARN(AC.ports[3].increment, "AC[3].increment"), SFVARN(AC.ports[3].control, "AC[3].control"),
SFVARN(AC.shift_bits, "ACShiftBits"),
SFVARN(AC.shift_latch, "ACShift"),
SFVARN(AC.rotate_bits, "ACRotateBits"),
SFARRAY(ACRAM, ACRAMUsed ? 0x200000 : 0x0),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, ACStateRegs, "ArcadeCard");
return(ret);
}
void ArcadeCard::PeekRAM(uint32 Address, uint32 Length, uint8 *Buffer)
{
while(Length--)
{
Address &= (1 << 21) - 1;
*Buffer = ACRAM[Address];
Address++;
Buffer++;
}
}
void ArcadeCard::PokeRAM(uint32 Address, uint32 Length, const uint8 *Buffer)
{
uint8 used = 0;
while(Length--)
{
Address &= (1 << 21) - 1;
ACRAM[Address] = *Buffer;
used |= ACRAM[Address];
Address++;
Buffer++;
}
if(used)
ACRAMUsed = true;
}

View File

@ -0,0 +1,55 @@
#ifndef __MDFN_PCE_ARCADE_CARD_H
#define __MDFN_PCE_ARCADE_CARD_H
typedef struct
{
uint32 base; // 24 bits
uint16 offset; // 16 bits
uint16 increment; // 16 bits
uint8 control; // 7 bits
} ACPort_t;
typedef struct
{
ACPort_t ports[4];
uint32 shift_latch; // 32 bits
uint8 shift_bits; // signed 4-bit value
uint8 rotate_bits; // same
} ArcadeCard_t;
class ArcadeCard
{
public:
ArcadeCard(void);
~ArcadeCard();
void Power(void);
int StateAction(StateMem *sm, int load, int data_only);
uint8 Read(uint32 A, bool peek = false); // Pass peek as true if you don't want side-effects from this read(IE in a debugger).
void Write(uint32 A, uint8 V);
INLINE void PhysWrite(uint32 A, uint8 V)
{
Write(0x1a00 | ((A >> 9) & 0x30), V);
}
INLINE uint8 PhysRead(uint32 A, bool peek = false)
{
return(Read(0x1a00 | ((A >> 9) & 0x30), peek));
}
void PeekRAM(uint32 Address, uint32 Length, uint8 *Buffer);
void PokeRAM(uint32 Address, uint32 Length, const uint8 *Buffer);
private:
ArcadeCard_t AC;
bool ACRAMUsed;
uint8 ACRAM[0x200000];
};
#endif

View File

@ -0,0 +1,862 @@
/* 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 "../../mednafen.h"
#include "pce_psg.h"
#include <math.h>
#include <string.h>
#include "../../include/trio/trio.h"
void PCE_PSG::SetVolume(double new_volume)
{
OutputVolume = new_volume;
Synth.volume(OutputVolume / 6);
}
// 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); }
void PCE_PSG::UpdateOutput_Norm(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
int sv = ch->dda;
samp[0] = dbtable[ch->vl[0]][sv];
samp[1] = dbtable[ch->vl[1]][sv];
Synth.offset(timestamp, samp[0] - ch->blip_prev_samp[0], sbuf[0]);
Synth.offset(timestamp, samp[1] - ch->blip_prev_samp[1], sbuf[1]);
ch->blip_prev_samp[0] = samp[0];
ch->blip_prev_samp[1] = samp[1];
}
void PCE_PSG::UpdateOutput_Noise(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
int sv = ((ch->lfsr & 1) << 5) - (ch->lfsr & 1); //(ch->lfsr & 0x1) ? 0x1F : 0;
samp[0] = dbtable[ch->vl[0]][sv];
samp[1] = dbtable[ch->vl[1]][sv];
Synth.offset(timestamp, samp[0] - ch->blip_prev_samp[0], sbuf[0]);
Synth.offset(timestamp, samp[1] - ch->blip_prev_samp[1], sbuf[1]);
ch->blip_prev_samp[0] = samp[0];
ch->blip_prev_samp[1] = samp[1];
}
void PCE_PSG::UpdateOutput_Off(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
samp[0] = samp[1] = 0;
Synth.offset_inline(timestamp, samp[0] - ch->blip_prev_samp[0], sbuf[0]);
Synth.offset_inline(timestamp, samp[1] - ch->blip_prev_samp[1], sbuf[1]);
ch->blip_prev_samp[0] = samp[0];
ch->blip_prev_samp[1] = samp[1];
}
void PCE_PSG::UpdateOutput_Accum(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
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);
Synth.offset_inline(timestamp, samp[0] - ch->blip_prev_samp[0], sbuf[0]);
Synth.offset_inline(timestamp, samp[1] - ch->blip_prev_samp[1], sbuf[1]);
ch->blip_prev_samp[0] = samp[0];
ch->blip_prev_samp[1] = 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 <= 0xA && (chnum != 1 || !(lfoctrl & 0x80)) )
ch->UpdateOutput = &PCE_PSG::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;
int32 tmp_freq = ((int32)ch->frequency + ((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 & 0x7FFF;
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 & 0x7FFF;
break;
}
}
PCE_PSG::PCE_PSG(Blip_Buffer *bb_l, Blip_Buffer *bb_r, int want_revision)
{
revision = want_revision;
sbuf[0] = bb_l;
sbuf[1] = bb_r;
SoundEnabled = (sbuf[0] && sbuf[1]);
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);
for(int vl = 0; vl < 32; vl++)
{
double flub = 1;
if(vl)
flub /= powf(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);
dbtable_volonly[vl] = (int32)(flub * 65536);
}
}
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;
if(REVISION_ENHANCED == revision)
{
for(int cht = 0; cht < 6; cht++)
for(int lr = 0; lr < 2; lr++)
channel[cht].vl[lr] = GetVL(cht, lr);
}
else
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);
if(REVISION_ENHANCED == revision)
{
ch->vl[0] = GetVL(select, 0);
ch->vl[1] = GetVL(select, 1);
}
else
vol_pending = true;
break;
case 0x05: /* Channel balance */
if(select > 5) return; // no more than 6 channels, silly game.
ch->balance = V;
if(REVISION_ENHANCED == revision)
{
ch->vl[0] = GetVL(select, 0);
ch->vl[1] = GetVL(select, 1);
}
else
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;
if(REVISION_ENHANCED == revision)
{
if(&PCE_PSG::UpdateOutput_Norm == ch->UpdateOutput)
UpdateOutput_Norm(timestamp, ch);
}
}
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.
inline 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;
//if(chc != 5)
// return;
if(REVISION_ENHANCED != revision)
(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 <= 0xA)
{
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 <= 0xA) ? 0xA : 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);
}
//static int32 last_read;
//static int32 last_apply;
void PCE_PSG::Update(int32 timestamp)
{
int32 run_time = timestamp - lastts;
if(!SoundEnabled)
return;
if(REVISION_ENHANCED != revision)
{
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(REVISION_ENHANCED != revision)
{
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(REVISION_ENHANCED != revision && 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::EndFrame(int32 timestamp)
{
Update(timestamp);
lastts = 0;
for(int chc = 0; chc < 6; chc++)
channel[chc].lastts = 0;
}
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);
memset(&channel, 0, sizeof(channel));
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;
}
int PCE_PSG::StateAction(StateMem *sm, int load, int data_only)
{
int ret = 1;
for(int ch = 0; ch < 6; ch++)
{
char tmpstr[5] = "SCHx";
psg_channel *pt = &channel[ch];
SFORMAT CH_StateRegs[] =
{
SFVARN(pt->counter, "counter"),
SFVARN(pt->frequency, "frequency"),
SFVARN(pt->control, "control"),
SFVARN(pt->balance, "balance"),
SFARRAYN(pt->waveform, 32, "waveform"),
SFVARN(pt->waveform_index, "waveform_index"),
SFVARN(pt->dda, "dda"),
SFVARN(pt->noisectrl, "noisectrl"),
SFVARN(pt->noisecount, "noisecount"),
SFVARN(pt->lfsr, "lfsr"),
SFARRAY32N(pt->vl, 2, "vl"), // TODO
SFEND
};
tmpstr[3] = '0' + ch;
ret &= MDFNSS_StateAction(sm, load, data_only, CH_StateRegs, tmpstr);
}
SFORMAT PSG_StateRegs[] =
{
SFVAR(select),
SFVAR(globalbalance),
SFVAR(lfofreq),
SFVAR(lfoctrl),
SFVAR(vol_update_counter),
SFVAR(vol_update_which),
SFVAR(vol_pending),
SFEND
};
ret &= MDFNSS_StateAction(sm, load, data_only, PSG_StateRegs, "PSG");
if(load)
{
vol_update_which &= 0x1F;
if(!channel[4].lfsr)
channel[4].lfsr = 1;
if(!channel[5].lfsr)
channel[5].lfsr = 1;
for(int ch = 0; ch < 6; ch++)
{
channel[ch].samp_accum = 0;
for(int wi = 0; wi < 32; wi++)
{
channel[ch].waveform[wi] &= 0x1F;
channel[ch].samp_accum += channel[ch].waveform[wi];
}
for(int lr = 0; lr < 2; lr++)
channel[ch].vl[lr] &= 0x1F;
if(!channel[ch].noisecount && ch >= 4)
{
printf("ch=%d, noisecount == 0\n", ch);
channel[ch].noisecount = 1;
}
if(channel[ch].counter <= 0)
{
printf("ch=%d, counter <= 0\n", ch);
channel[ch].counter = 1;
}
if(ch >= 4)
RecalcNoiseFreqCache(ch);
RecalcFreqCache(ch);
RecalcUOFunc(ch);
}
}
return(ret);
}

View File

@ -0,0 +1,180 @@
#ifndef _PCE_PSG_H
#define _PCE_PSG_H
#include "../../include/blip/Blip_Buffer.h"
#include "../../include/blip/Stereo_Buffer.h"
class PCE_PSG;
struct psg_channel
{
int32 counter;
uint16 frequency; /* Channel frequency */
uint32 freq_cache;
uint8 control; /* Channel enable, DDA, volume */
uint8 balance; /* Channel balance */
uint8 waveform[32]; /* Waveform data */
uint8 waveform_index; /* Waveform data index */
uint8 dda;
uint8 noisectrl; /* Noise enable/ctrl (channels 4,5 only) */
uint32 noise_freq_cache; // Channel 4,5 only
int32 noisecount;
uint32 lfsr;
//int32 sample_cache[2];
int32 vl[2]; //vll, vlr;
int 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;
void (PCE_PSG::*UpdateOutput)(const int32 timestamp, psg_channel *ch);
};
// 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_ENHANCED,
_REVISION_COUNT
};
PCE_PSG(Blip_Buffer *bb_l, Blip_Buffer *bb_r, int want_revision);
~PCE_PSG();
int StateAction(StateMem *sm, int load, int data_only);
void Power(const int32 timestamp);
void Write(int32 timestamp, uint8 A, uint8 V);
void SetVolume(double new_volume);
void EndFrame(int32 timestamp);
// 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 Update(int32 timestamp);
void UpdateSubLFO(int32 timestamp);
void UpdateSubNonLFO(int32 timestamp);
void RecalcUOFunc(int chnum);
void UpdateOutput_Off(const int32 timestamp, psg_channel *ch);
void UpdateOutput_Accum(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 UpdateOutput_Norm_IL(const int32 timestamp, psg_channel *ch);
// void UpdateOutput_Noise_IL(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);
double OutputVolume;
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;
bool SoundEnabled;
Blip_Buffer *sbuf[2];
Blip_Synth<blip_good_quality, 8192> Synth;
int32 dbtable_volonly[32];
int32 dbtable[32][32];
};
#endif

View File

@ -0,0 +1,20 @@
0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x61,0x61,0x1e,0x17,0xf0,0x7f,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x13,0x41,0x16,0x0e,0xfd,0xf4,0x23,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0x01,0x9a,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x11,0x61,0x0e,0x07,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x22,0x16,0x05,0xf0,0x71,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x61,0x1d,0x07,0x82,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x23,0x21,0x2d,0x16,0x90,0x90,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x21,0x1b,0x06,0x64,0x65,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x21,0x0b,0x1a,0x85,0xa0,0x70,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x23,0x01,0x83,0x10,0xff,0xb4,0x10,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x97,0xc1,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x61,0x00,0x0c,0x05,0xc2,0xf6,0x40,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x01,0x56,0x03,0x94,0xc2,0x03,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x01,0x89,0x03,0xf1,0xe4,0xf0,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,123 @@
#ifndef _EMU2413_H_
#define _EMU2413_H_
#define PI 3.14159265358979323846
enum {EMU2413_2413_TONE = 0};
/* voice data */
typedef struct {
uint32 TL,FB,EG,ML,AR,DR,SL,RR,KR,KL,AM,PM,WF ;
} EMU2413_PATCH ;
/* slot */
typedef struct {
EMU2413_PATCH *patch;
int32 type ; /* 0 : modulator 1 : carrier */
/* OUTPUT */
int32 feedback ;
int32 output[2] ; /* Output value of slot */
/* for Phase Generator (PG) */
uint32 *sintbl ; /* Wavetable */
uint32 phase ; /* Phase */
uint32 dphase ; /* Phase increment amount */
uint32 pgout ; /* output */
/* for Envelope Generator (EG) */
int32 fnum ; /* F-Number */
int32 block ; /* Block */
int32 volume ; /* Current volume */
int32 sustine ; /* Sustine 1 = ON, 0 = OFF */
uint32 tll ; /* Total Level + Key scale level*/
uint32 rks ; /* Key scale offset (Rks) */
int32 eg_mode ; /* Current state */
uint32 eg_phase ; /* Phase */
uint32 eg_dphase ; /* Phase increment amount */
uint32 egout ; /* output */
} EMU2413_SLOT ;
/* Mask */
#define EMU2413_MASK_CH(x) (1<<(x))
#define EMU2413_MASK_HH (1<<(9))
#define EMU2413_MASK_CYM (1<<(10))
#define EMU2413_MASK_TOM (1<<(11))
#define EMU2413_MASK_SD (1<<(12))
#define EMU2413_MASK_BD (1<<(13))
#define EMU2413_MASK_RHYTHM ( EMU2413_MASK_HH | EMU2413_MASK_CYM | EMU2413_MASK_TOM | EMU2413_MASK_SD | EMU2413_MASK_BD )
/* opll */
typedef struct
{
uint32 adr ;
int32 out ;
uint32 pan[16];
/* Register */
uint8 reg[0x40] ;
int32 slot_on_flag[18] ;
/* Pitch Modulator */
uint32 pm_phase ;
int32 lfo_pm ;
/* Amp Modulator */
int32 am_phase ;
int32 lfo_am ;
/* Noise Generator */
uint32 noise_seed ;
/* Channel Data */
int32 patch_number[9];
int32 key_status[9] ;
/* Slot */
EMU2413_SLOT slot[18] ;
/* Voice Data */
EMU2413_PATCH patch[19*2] ;
int32 patch_update[2] ; /* flag for check patch update */
uint32 mask ;
} EMU2413 ;
/* Create Object */
EMU2413 *EMU2413_new(uint32 clk);
void EMU2413_delete(EMU2413 *);
/* Setup */
void EMU2413_reset(EMU2413 *);
void EMU2413_reset_patch(EMU2413 *, int32);
void EMU2413_set_pan(EMU2413 *, uint32 ch, uint32 pan);
/* Port/Register access */
void EMU2413_writeIO(EMU2413 *, uint32 reg, uint32 val) ;
void EMU2413_writeReg(EMU2413 *, uint32 reg, uint32 val) ;
/* Synthsize */
int32 EMU2413_calc(EMU2413 *) ;
void EMU2413_calc_stereo(EMU2413 *, int32 out[2]) ;
/* Misc */
void EMU2413_setPatch(EMU2413 *, const uint8 *dump) ;
void EMU2413_copyPatch(EMU2413 *, int32, EMU2413_PATCH *) ;
void EMU2413_forceRefresh(EMU2413 *) ;
/* Utility */
void EMU2413_dump2patch(const uint8 *dump, EMU2413_PATCH *patch) ;
void EMU2413_patch2dump(const EMU2413_PATCH *patch, uint8 *dump) ;
void EMU2413_getDefaultPatch(int32 type, int32 num, EMU2413_PATCH *) ;
/* Channel Mask */
uint32 EMU2413_setMask(EMU2413 *, uint32 mask) ;
uint32 EMU2413_toggleMask(EMU2413 *, uint32 mask) ;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,435 @@
#ifndef __PCE_VDC_H
#define __PCE_VDC_H
#include "mednafen/lepacker.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;
} VDC_SimulateResult;
class VDC
{
public:
// The VRAM size is specified in 16-bit words.
VDC(bool nospritelimit, uint32 par_VRAM_Size);
~VDC();
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->ReadStart = 0;
result->WriteStart = 0;
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->ReadStart = 0;
result->WriteStart = 0;
const unsigned int msb = A & 1;
switch(A & 0x3)
{
case 0x00: Simulate_select = V & 0x1F;
break;
case 0x02:
case 0x03:
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;
}
}
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);
bool ToggleLayer(int);
void RunDMA(int32, bool force_completion = FALSE);
void RunSATDMA(int32, bool force_completion = FALSE);
void IncRCR(void);
void DoVBIRQTest(void);
void HDS_Start(void);
void StateExtra(MDFN::LEPacker &sl_packer, bool load);
int StateAction(StateMem *sm, int load, int data_only, const char *sname);
// 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;
}
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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,435 @@
#ifndef __PCE_VDC_H
#define __PCE_VDC_H
#include "../../lepacker.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;
} VDC_SimulateResult;
class VDC
{
public:
// The VRAM size is specified in 16-bit words.
VDC(bool nospritelimit, uint32 par_VRAM_Size);
~VDC();
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->ReadStart = 0;
result->WriteStart = 0;
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->ReadStart = 0;
result->WriteStart = 0;
const unsigned int msb = A & 1;
switch(A & 0x3)
{
case 0x00: Simulate_select = V & 0x1F;
break;
case 0x02:
case 0x03:
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;
}
}
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);
void StateExtra(MDFN::LEPacker &sl_packer, bool load);
int StateAction(StateMem *sm, int load, int data_only, const char *sname);
// 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;
}
private:
int TimeFromHDSStartToBYRLatch(void);
int TimeFromBYRLatchToBXRLatch(void);
enum
{
HPHASE_HDS = 0,
HPHASE_HDS_PART2,
HPHASE_HDS_PART3,
HPHASE_HDW,
HPHASE_HDW_FINAL,
HPHASE_HDE,
HPHASE_HSW,
HPHASE_COUNT
};
enum
{
VPHASE_VDS = 0,
VPHASE_VDW,
VPHASE_VCR,
VPHASE_VSW,
VPHASE_COUNT
};
int VRAM_Size; // = 0x8000;
int VRAM_SizeMask; // = VRAM_Size - 1; //0x7FFF;
int VRAM_BGTileNoMask; // = VRAM_SizeMask / 16; //0x7FF;
void (*IRQHook)(bool);
bool (*WSHook)(int32);
void DoWaitStates(void);
void CheckAndCommitPending(void);
INLINE int32 CalcNextEvent(void)
{
int32 next_event = HPhaseCounter;
if(sat_dma_counter > 0 && sat_dma_counter < next_event)
next_event = sat_dma_counter;
if(sprite_cg_fetch_counter > 0 && sprite_cg_fetch_counter < next_event)
next_event = sprite_cg_fetch_counter;
if(DMARunning)
{
assert(VDMA_CycleCounter < 2);
int32 next_vram_dma_event = ((LENR + 1) * 4) - (DMAReadWrite * 2) - VDMA_CycleCounter;
assert(next_vram_dma_event > 0);
if(next_vram_dma_event > 0 && next_vram_dma_event < next_event)
next_event = next_vram_dma_event;
//printf("Next VRAM DMA event: %d(LENR = %d)\n", next_vram_dma_event, LENR);
}
assert(next_event > 0);
return(next_event);
}
bool in_exhsync, in_exvsync;
void CalcWidthStartEnd(uint32 &display_width, uint32 &start, uint32 &end);
void DrawBG(uint16 *target, int enabled);
void DrawSprites(uint16 *target, int enabled);
void FetchSpriteData(void);
uint8 Simulate_select;
uint16 Simulate_MAWR;
uint16 Simulate_MARR;
uint16 Simulate_CR;
uint16 Simulate_LENR;
int32 sat_dma_counter;
uint8 select;
uint16 MAWR; // Memory Address Write Register
uint16 MARR; // Memory Address Read Register
uint16 CR; // Control Register
uint16 CR_cache; // Cache for BG/SPR enable
uint16 RCR; // Raster Compare Register
uint16 BXR; // Background X-Scroll Register
uint16 BYR; // Background Y-Scroll Register
uint16 MWR; // Memory Width Register
uint16 HSR; // Horizontal Sync Register
uint16 HDR; // Horizontal Display Register
uint16 VSR;
uint16 VDR;
uint16 VCR;
uint16 DCR;
uint16 SOUR;
uint16 DESR;
uint16 LENR;
uint16 DVSSR;
// Internal SAT DMA transfer variables.
//uint16 SAT_SOUR;
//uint16 SAT_DESR;
//uint16 SAT_LENR;
int32 VDMA_CycleCounter;
uint32 RCRCount;
bool pending_read;
uint16 pending_read_addr;
uint16 read_buffer;
uint8 write_latch; // LSB
bool pending_write;
uint16 pending_write_addr;
uint16 pending_write_latch;
uint8 status;
uint16 SAT[0x100];
uint16 VRAM[65536]; //VRAM_Size];
union
{
uint64 bg_tile_cache64[65536 / 16][8]; // Tile, y, x
uint8 bg_tile_cache[65536 / 16][8][8];
};
uint16 DMAReadBuffer;
bool DMAReadWrite;
bool DMARunning;
bool DMAPending;
bool SATBPending;
bool burst_mode;
uint32 BG_YOffset; // Reloaded from BYR at start of display area?
uint32 BG_XOffset; // Reloaded from BXR at each scanline, methinks.
uint32 HSW_cache, HDS_cache, HDW_cache, HDE_cache;
uint32 VDS_cache;
uint32 VSW_cache;
uint32 VDW_cache;
uint32 VCR_cache;
uint16 MWR_cache;
uint32 BG_YMoo;
bool NeedRCRInc, NeedVBIRQTest, NeedSATDMATest, NeedBGYInc;
int HPhase, VPhase;
int32 HPhaseCounter, VPhaseCounter;
int32 sprite_cg_fetch_counter;
int32 mystery_counter;
bool mystery_phase;
uint16 linebuf[1024 + 512];
uint32 pixel_desu;
int32 pixel_copy_count;
uint32 userle; // User layer enable.
bool unlimited_sprites;
int active_sprites;
SPRLE SpriteList[64 * 2]; // (see unlimited_sprites option, *2 to accommodate 32-pixel-width sprites ) //16];
};
#endif

View File

@ -139,9 +139,6 @@ void MDFNI_CloseGame(void)
#endif
}
#ifdef WANT_PSX_EMU
extern MDFNGI EmulatedPSX;
#endif
std::vector<MDFNGI *> MDFNSystems;
static std::list<MDFNGI *> MDFNSystemsPrio;
@ -612,6 +609,14 @@ MDFNGI *MDFNI_LoadGame(const char *force_module, const char *name)
return(MDFNGameInfo);
}
#if defined(WANT_PSX_EMU)
extern MDFNGI EmulatedPSX;
#elif defined(WANT_PCE_EMU)
extern MDFNGI EmulatedPCE;
#elif defined(WANT_PCE_FAST_EMU)
extern MDFNGI EmulatedPCE_Fast;
#endif
bool MDFNI_InitializeModules(const std::vector<MDFNGI *> &ExternalSystems)
{
static MDFNGI *InternalSystems[] =

View File

@ -0,0 +1,8 @@
AUTOMAKE_OPTIONS = subdir-objects
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@ @MATH_OPTIMIZER_FLAGS@
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_srcdir)/src/hw_misc -I$(top_srcdir)/src/hw_sound
noinst_LIBRARIES = libpce_fast.a
mednafen_SOURCES = huc6280.cpp pce.cpp vdc.cpp input.cpp huc.cpp hes.cpp tsushin.cpp
libpce_fast_a_SOURCES = $(mednafen_SOURCES)

View File

@ -0,0 +1,605 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
subdir = src/pce_fast
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cflags_gcc_option.m4 \
$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/fcntl-o.m4 \
$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \
$(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \
$(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \
$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \
$(top_srcdir)/m4/inttypes-pri.m4 \
$(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
$(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \
$(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \
$(top_srcdir)/m4/threadlib.m4 $(top_srcdir)/m4/uintmax_t.m4 \
$(top_srcdir)/m4/visibility.m4 $(top_srcdir)/m4/wchar_t.m4 \
$(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xsize.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/include/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LIBRARIES = $(noinst_LIBRARIES)
ARFLAGS = cru
AM_V_AR = $(am__v_AR_$(V))
am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY))
am__v_AR_0 = @echo " AR " $@;
AM_V_at = $(am__v_at_$(V))
am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
am__v_at_0 = @
libpce_fast_a_AR = $(AR) $(ARFLAGS)
libpce_fast_a_LIBADD =
am__objects_1 = huc6280.$(OBJEXT) pce.$(OBJEXT) vdc.$(OBJEXT) \
input.$(OBJEXT) huc.$(OBJEXT) hes.$(OBJEXT) tsushin.$(OBJEXT)
am_libpce_fast_a_OBJECTS = $(am__objects_1)
libpce_fast_a_OBJECTS = $(am_libpce_fast_a_OBJECTS)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
am__v_lt_0 = --silent
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_$(V))
am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY))
am__v_CXX_0 = @echo " CXX " $@;
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_$(V))
am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY))
am__v_CXXLD_0 = @echo " CXXLD " $@;
AM_V_GEN = $(am__v_GEN_$(V))
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(libpce_fast_a_SOURCES)
DIST_SOURCES = $(libpce_fast_a_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AM_CFLAGS = @AM_CFLAGS@
AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
CATOBJEXT = @CATOBJEXT@
CC = @CC@
CCAS = @CCAS@
CCASDEPMODE = @CCASDEPMODE@
CCASFLAGS = @CCASFLAGS@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DATADIRNAME = @DATADIRNAME@
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@ @MATH_OPTIMIZER_FLAGS@
DEPDIR = @DEPDIR@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GBA_EXTRA_FLAGS = @GBA_EXTRA_FLAGS@
GENCAT = @GENCAT@
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
GLIBC2 = @GLIBC2@
GLIBC21 = @GLIBC21@
GMSGFMT = @GMSGFMT@
GMSGFMT_015 = @GMSGFMT_015@
GREP = @GREP@
HAVE_ASPRINTF = @HAVE_ASPRINTF@
HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@
HAVE_SNPRINTF = @HAVE_SNPRINTF@
HAVE_VISIBILITY = @HAVE_VISIBILITY@
HAVE_WPRINTF = @HAVE_WPRINTF@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INSTOBJEXT = @INSTOBJEXT@
INTLBISON = @INTLBISON@
INTLLIBS = @INTLLIBS@
INTLOBJS = @INTLOBJS@
INTL_DEFAULT_VERBOSITY = @INTL_DEFAULT_VERBOSITY@
INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
JACK_CFLAGS = @JACK_CFLAGS@
JACK_LIBS = @JACK_LIBS@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCDIO_CFLAGS = @LIBCDIO_CFLAGS@
LIBCDIO_LIBS = @LIBCDIO_LIBS@
LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBMULTITHREAD = @LIBMULTITHREAD@
LIBOBJS = @LIBOBJS@
LIBPTH = @LIBPTH@
LIBPTH_PREFIX = @LIBPTH_PREFIX@
LIBS = @LIBS@
LIBTHREAD = @LIBTHREAD@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBC = @LTLIBC@
LTLIBICONV = @LTLIBICONV@
LTLIBINTL = @LTLIBINTL@
LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
LTLIBOBJS = @LTLIBOBJS@
LTLIBPTH = @LTLIBPTH@
LTLIBTHREAD = @LTLIBTHREAD@
MAKEINFO = @MAKEINFO@
MATH_OPTIMIZER_FLAGS = @MATH_OPTIMIZER_FLAGS@
MKDIR_P = @MKDIR_P@
MMX_CFLAGS = @MMX_CFLAGS@
MSGFMT = @MSGFMT@
MSGFMT_015 = @MSGFMT_015@
MSGMERGE = @MSGMERGE@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POSUB = @POSUB@
PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@
RANLIB = @RANLIB@
SDL_CFLAGS = @SDL_CFLAGS@
SDL_CONFIG = @SDL_CONFIG@
SDL_LIBS = @SDL_LIBS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
SNDFILE_LIBS = @SNDFILE_LIBS@
SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
SSE2_CFLAGS = @SSE2_CFLAGS@
SSE3_CFLAGS = @SSE3_CFLAGS@
SSE_CFLAGS = @SSE_CFLAGS@
STRIP = @STRIP@
TRIO_CFLAGS = @TRIO_CFLAGS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARNING_FLAGS = @WARNING_FLAGS@
WINDRES = @WINDRES@
WOE32 = @WOE32@
WOE32DLL = @WOE32DLL@
XGETTEXT = @XGETTEXT@
XGETTEXT_015 = @XGETTEXT_015@
XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
XMKMF = @XMKMF@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
lt_ECHO = @lt_ECHO@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = subdir-objects
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_srcdir)/src/hw_misc -I$(top_srcdir)/src/hw_sound
noinst_LIBRARIES = libpce_fast.a
mednafen_SOURCES = huc6280.cpp pce.cpp vdc.cpp input.cpp huc.cpp hes.cpp tsushin.cpp
libpce_fast_a_SOURCES = $(mednafen_SOURCES)
all: all-am
.SUFFIXES:
.SUFFIXES: .cpp .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pce_fast/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/pce_fast/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
libpce_fast.a: $(libpce_fast_a_OBJECTS) $(libpce_fast_a_DEPENDENCIES)
$(AM_V_at)-rm -f libpce_fast.a
$(AM_V_AR)$(libpce_fast_a_AR) libpce_fast.a $(libpce_fast_a_OBJECTS) $(libpce_fast_a_LIBADD)
$(AM_V_at)$(RANLIB) libpce_fast.a
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hes.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huc6280.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pce.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsushin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vdc.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cpp.lo:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LIBRARIES)
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
clean-libtool clean-noinstLIBRARIES ctags distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags uninstall uninstall-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,407 @@
/* Mednafen - Multi-system Emulator
*
* Portions of this file Copyright (C) 2004 Ki
*
* 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 "pce.h"
#include <errno.h>
#include "../cdrom/pcecd.h"
#include "../hw_misc/arcade_card/arcade_card.h"
#include "../md5.h"
#include "../file.h"
#include "../cdrom/cdromif.h"
#include "../mempatcher.h"
static const char BRAM_Init_String[8] = { 'H', 'U', 'B', 'M', 0x00, 0x88, 0x10, 0x80 }; //"HUBM\x00\x88\x10\x80";
ArcadeCard *arcade_card = NULL;
static uint8 *HuCROM = NULL;
static bool IsPopulous;
bool IsTsushin;
bool PCE_IsCD;
static uint8 *TsushinRAM = NULL; // 0x8000
static uint8 SaveRAM[2048];
static DECLFW(ACPhysWrite)
{
arcade_card->PhysWrite(A, V);
}
static DECLFR(ACPhysRead)
{
return(arcade_card->PhysRead(A));
}
static DECLFR(SaveRAMRead)
{
if((!PCE_IsCD || PCECD_IsBRAMEnabled()) && (A & 8191) < 2048)
return(SaveRAM[A & 2047]);
else
return(0xFF);
}
static DECLFW(SaveRAMWrite)
{
if((!PCE_IsCD || PCECD_IsBRAMEnabled()) && (A & 8191) < 2048)
SaveRAM[A & 2047] = V;
}
static DECLFR(HuCRead)
{
return ROMSpace[A];
}
static DECLFW(HuCRAMWrite)
{
ROMSpace[A] = V;
}
static DECLFW(HuCRAMWriteCDSpecial) // Hyper Dyne Special hack
{
BaseRAM[0x2000 | (A & 0x1FFF)] = V;
ROMSpace[A] = V;
}
static uint8 HuCSF2Latch = 0;
static DECLFR(HuCSF2Read)
{
return(HuCROM[(A & 0x7FFFF) + 0x80000 + HuCSF2Latch * 0x80000 ]); // | (HuCSF2Latch << 19) ]);
}
static DECLFW(HuCSF2Write)
{
if((A & 0x1FFC) == 0x1FF0)
{
HuCSF2Latch = (A & 0x3);
}
}
int HuCLoad(const uint8 *data, uint32 len, uint32 crc32)
{
uint32 sf2_threshold = 2048 * 1024;
uint32 sf2_required_size = 2048 * 1024 + 512 * 1024;
uint32 m_len = (len + 8191)&~8191;
bool sf2_mapper = FALSE;
if(m_len >= sf2_threshold)
{
sf2_mapper = TRUE;
if(m_len != sf2_required_size)
m_len = sf2_required_size;
}
IsPopulous = 0;
PCE_IsCD = 0;
md5_context md5;
md5.starts();
md5.update(data, len);
md5.finish(MDFNGameInfo->MD5);
MDFN_printf(_("ROM: %dKiB\n"), (len + 1023) / 1024);
MDFN_printf(_("ROM CRC32: 0x%04x\n"), crc32);
MDFN_printf(_("ROM MD5: 0x%s\n"), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
if(!(HuCROM = (uint8 *)MDFN_malloc(m_len, _("HuCard ROM"))))
{
return(0);
}
memset(HuCROM, 0xFF, m_len);
memcpy(HuCROM, data, len);
memset(ROMSpace, 0xFF, 0x88 * 8192 + 8192);
if(m_len == 0x60000)
{
memcpy(ROMSpace + 0x00 * 8192, HuCROM, 0x20 * 8192);
memcpy(ROMSpace + 0x20 * 8192, HuCROM, 0x20 * 8192);
memcpy(ROMSpace + 0x40 * 8192, HuCROM + 0x20 * 8192, 0x10 * 8192);
memcpy(ROMSpace + 0x50 * 8192, HuCROM + 0x20 * 8192, 0x10 * 8192);
memcpy(ROMSpace + 0x60 * 8192, HuCROM + 0x20 * 8192, 0x10 * 8192);
memcpy(ROMSpace + 0x70 * 8192, HuCROM + 0x20 * 8192, 0x10 * 8192);
}
else if(m_len == 0x80000)
{
memcpy(ROMSpace + 0x00 * 8192, HuCROM, 0x40 * 8192);
memcpy(ROMSpace + 0x40 * 8192, HuCROM + 0x20 * 8192, 0x20 * 8192);
memcpy(ROMSpace + 0x60 * 8192, HuCROM + 0x20 * 8192, 0x20 * 8192);
}
else
{
memcpy(ROMSpace + 0x00 * 8192, HuCROM, (m_len < 1024 * 1024) ? m_len : 1024 * 1024);
}
for(int x = 0x00; x < 0x80; x++)
{
HuCPUFastMap[x] = ROMSpace;
PCERead[x] = HuCRead;
}
if(!memcmp(HuCROM + 0x1F26, "POPULOUS", strlen("POPULOUS")))
{
uint8 *PopRAM = ROMSpace + 0x40 * 8192;
FILE *fp;
memset(PopRAM, 0xFF, 32768);
if((fp = fopen(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), "rb")))
{
fread(PopRAM, 32768, 1, fp);
fclose(fp);
}
IsPopulous = 1;
MDFN_printf("Populous\n");
for(int x = 0x40; x < 0x44; x++)
{
HuCPUFastMap[x] = &PopRAM[(x & 3) * 8192] - x * 8192;
PCERead[x] = HuCRead;
PCEWrite[x] = HuCRAMWrite;
}
MDFNMP_AddRAM(32768, 0x40 * 8192, PopRAM);
}
else if(crc32 == 0x34dc65c4) // Tsushin Booster
{
FILE *fp;
if(!(TsushinRAM = (uint8*)MDFN_calloc(1, 0x8000 + 8192, _("Tsushin Booster RAM")))) // + 8192 for PC-as-ptr safety padding
{
MDFN_free(HuCROM);
return(0);
}
memset(TsushinRAM, 0xFF, 0x8000);
if((fp = fopen(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), "rb")))
{
fread(TsushinRAM, 32768, 1, fp);
fclose(fp);
}
IsTsushin = 1;
MDFN_printf("Tsushin Booster\n");
for(int x = 0x88; x < 0x8C; x++)
{
HuCPUFastMap[x] = &TsushinRAM[(x & 3) * 8192] - x * 8192;
PCERead[x] = HuCRead;
PCEWrite[x] = HuCRAMWrite;
}
MDFNMP_AddRAM(32768, 0x88 * 8192, TsushinRAM);
}
else
{
FILE * fp;
memset(SaveRAM, 0x00, 2048);
memcpy(SaveRAM, BRAM_Init_String, 8); // So users don't have to manually intialize the file cabinet
// in the CD BIOS screen.
if((fp = fopen(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), "rb")))
{
fread(SaveRAM, 2048, 1, fp);
fclose(fp);
}
PCEWrite[0xF7] = SaveRAMWrite;
PCERead[0xF7] = SaveRAMRead;
MDFNMP_AddRAM(2048, 0xF7 * 8192, SaveRAM);
}
// 0x1A558
//if(len >= 0x20000 && !memcmp(HuCROM + 0x1A558, "STREET FIGHTER#", strlen("STREET FIGHTER#")))
if(sf2_mapper)
{
for(int x = 0x40; x < 0x80; x++)
{
// FIXME: PCE_FAST
HuCPUFastMap[x] = NULL; // Make sure our reads go through our read function, and not a table lookup
PCERead[x] = HuCSF2Read;
}
PCEWrite[0] = HuCSF2Write;
MDFN_printf("Street Fighter 2 Mapper\n");
HuCSF2Latch = 0;
}
return(1);
}
bool IsBRAMUsed(void)
{
if(memcmp(SaveRAM, BRAM_Init_String, 8)) // HUBM string is modified/missing
return(1);
for(int x = 8; x < 2048; x++)
if(SaveRAM[x]) return(1);
return(0);
}
int HuCLoadCD(const char *bios_path)
{
static const FileExtensionSpecStruct KnownBIOSExtensions[] =
{
{ ".pce", gettext_noop("PC Engine ROM Image") },
{ ".bin", gettext_noop("PC Engine ROM Image") },
{ ".bios", gettext_noop("BIOS Image") },
{ NULL, NULL }
};
MDFNFILE fp;
if(!fp.Open(bios_path, KnownBIOSExtensions, "CD BIOS"))
return(0);
memset(ROMSpace, 0xFF, 262144);
memcpy(ROMSpace, fp.f_data + (fp.f_size & 512), ((fp.f_size & ~512) > 262144) ? 262144 : (fp.f_size &~ 512) );
fp.Close();
PCE_IsCD = 1;
PCE_InitCD();
md5_context md5;
md5.starts();
MDFN_printf(_("Arcade Card Emulation: %s\n"), PCE_ACEnabled ? _("Enabled") : _("Disabled"));
for(int x = 0; x < 0x40; x++)
{
HuCPUFastMap[x] = ROMSpace;
PCERead[x] = HuCRead;
}
for(int x = 0x68; x < 0x88; x++)
{
HuCPUFastMap[x] = ROMSpace;
PCERead[x] = HuCRead;
PCEWrite[x] = HuCRAMWrite;
}
PCEWrite[0x80] = HuCRAMWriteCDSpecial; // Hyper Dyne Special hack
MDFNMP_AddRAM(262144, 0x68 * 8192, ROMSpace + 0x68 * 8192);
if(PCE_ACEnabled)
{
try
{
arcade_card = new ArcadeCard();
}
catch(std::exception &e)
{
MDFN_PrintError(_("Error creating %s object: %s"), "ArcadeCard", e.what());
return(0);
}
for(int x = 0x40; x < 0x44; x++)
{
HuCPUFastMap[x] = NULL;
PCERead[x] = ACPhysRead;
PCEWrite[x] = ACPhysWrite;
}
}
FILE *srp;
memset(SaveRAM, 0x00, 2048);
memcpy(SaveRAM, BRAM_Init_String, 8); // So users don't have to manually intialize the file cabinet
// in the CD BIOS screen.
if((srp = fopen(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), "rb")))
{
fread(SaveRAM, 2048, 1, srp);
fclose(srp);
}
PCEWrite[0xF7] = SaveRAMWrite;
PCERead[0xF7] = SaveRAMRead;
MDFNMP_AddRAM(2048, 0xF7 * 8192, SaveRAM);
return(1);
}
int HuC_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFARRAY(ROMSpace + 0x40 * 8192, IsPopulous ? 32768 : 0),
SFARRAY(TsushinRAM, IsTsushin ? 32768 : 0),
SFARRAY(SaveRAM, (IsPopulous || IsTsushin) ? 0 : 2048),
SFARRAY(ROMSpace + 0x68 * 8192, PCE_IsCD ? 262144 : 0),
SFVAR(HuCSF2Latch),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "HuC");
if(load)
HuCSF2Latch &= 0x3;
if(PCE_IsCD)
{
ret &= PCECD_StateAction(sm, load, data_only);
if(arcade_card)
ret &= arcade_card->StateAction(sm, load, data_only);
}
return(ret);
}
void HuCClose(void)
{
if(IsPopulous)
{
MDFN_DumpToFile(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), 6, ROMSpace + 0x40 * 8192, 32768);
}
else if(IsTsushin)
{
if(TsushinRAM)
{
MDFN_DumpToFile(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), 6, TsushinRAM, 32768);
MDFN_free(TsushinRAM);
TsushinRAM = NULL;
}
}
else if(IsBRAMUsed())
{
MDFN_DumpToFile(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), 6, SaveRAM, 2048);
}
if(arcade_card)
{
delete arcade_card;
arcade_card = NULL;
}
if(PCE_IsCD)
{
PCECD_Close();
}
if(HuCROM)
{
MDFN_free(HuCROM);
HuCROM = NULL;
}
}
void HuC_Power(void)
{
if(PCE_IsCD)
memset(ROMSpace + 0x68 * 8192, 0x00, 262144);
if(arcade_card)
arcade_card->Power();
}

View File

@ -0,0 +1,12 @@
int HuCLoad(const uint8 *data, uint32 len, uint32 crc32);
int HuCLoadCD(const char *bios_path);
void HuCClose(void);
int HuC_StateAction(StateMem *sm, int load, int data_only);
void HuC_Power(void);
DECLFR(PCE_ACRead);
DECLFW(PCE_ACWrite);
extern bool PCE_IsCD;
extern bool IsTsushin;

View File

@ -0,0 +1,635 @@
/* Mednafen - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* 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
*/
#define TEST_WEIRD_TFLAG(n) { if(HU_P & T_FLAG) puts("RAWR" n); }
case 0x00: /* BRK */
IncPC();
HU_P &= ~T_FLAG;
PUSH_PC();
COMPRESS_FLAGS();
PUSH(HU_P|B_FLAG);
HU_P|=I_FLAG;
HU_P &= ~D_FLAG;
HU_PI|=I_FLAG;
{
unsigned int npc;
npc=RdOp(0xFFF6);
npc|=RdOp(0xFFF7)<<8;
SetPC(npc);
}
break;
case 0x40: /* RTI */
HU_P = POP();
EXPAND_FLAGS();
/* HU_PI=HU_P; This is probably incorrect, so it's commented out. */
HU_PI = HU_P;
POP_PC();
// T-flag handling here:
TEST_WEIRD_TFLAG("RTI");
break;
case 0x60: /* RTS */
POP_PC_AP();
break;
case 0x48: /* PHA */
PUSH(HU_A);
break;
case 0x08: /* PHP */
HU_P &= ~T_FLAG;
COMPRESS_FLAGS();
PUSH(HU_P|B_FLAG);
break;
case 0xDA: // PHX 65C02
PUSH(HU_X);
break;
case 0x5A: // PHY 65C02
PUSH(HU_Y);
break;
case 0x68: /* PLA */
HU_A = POP();
X_ZN(HU_A);
break;
case 0xFA: // PLX 65C02
HU_X = POP();
X_ZN(HU_X);
break;
case 0x7A: // PLY 65C02
HU_Y = POP();
X_ZN(HU_Y);
break;
case 0x28: /* PLP */
HU_P = POP();
EXPAND_FLAGS();
// T-flag handling here:
TEST_WEIRD_TFLAG("PLP");
break;
case 0x4C:
{
unsigned int npc;
npc = RdAtPC();
IncPC();
npc|=RdAtPC() << 8;
SetPC(npc);
}
break; /* JMP ABSOLUTE */
case 0x6C: /* JMP Indirect */
{
uint32 tmp;
unsigned int npc;
GetAB(tmp);
npc=RdMem(tmp);
npc|=RdMem(tmp + 1)<<8;
SetPC(npc);
}
break;
case 0x7C: // JMP Indirect X - 65C02
{
uint32 tmp;
unsigned int npc;
GetAB(tmp);
tmp += HU_X;
npc=RdMem(tmp);
npc|=RdMem(tmp + 1)<<8;
SetPC(npc);
}
break;
case 0x20: /* JSR */
{
unsigned int npc;
npc = RdAtPC();
IncPC();
PUSH_PC();
npc |= RdAtPC() <<8;
SetPC(npc);
}
break;
case 0xAA: /* TAX */
HU_X=HU_A;
X_ZN(HU_A);
break;
case 0x8A: /* TXA */
HU_A=HU_X;
X_ZN(HU_A);
break;
case 0xA8: /* TAY */
HU_Y=HU_A;
X_ZN(HU_A);
break;
case 0x98: /* TYA */
HU_A=HU_Y;
X_ZN(HU_A);
break;
case 0xBA: /* TSX */
HU_X=HU_S;
X_ZN(HU_X);
break;
case 0x9A: /* TXS */
HU_S=HU_X;
break;
case 0xCA: /* DEX */
HU_X--;
X_ZN(HU_X);
break;
case 0x88: /* DEY */
HU_Y--;
X_ZN(HU_Y);
break;
case 0xE8: /* INX */
HU_X++;
X_ZN(HU_X);
break;
case 0xC8: /* INY */
HU_Y++;
X_ZN(HU_Y);
break;
case 0x54: CSL; break;
case 0xD4: CSH; break;
case 0x62: HU_A = 0; break; // CLA
case 0x82: HU_X = 0; break; // CLX
case 0xC2: HU_Y = 0; break; // CLY
case 0x18: /* CLC */
HU_P&=~C_FLAG;
break;
case 0xD8: /* CLD */
HU_P&=~D_FLAG;
break;
case 0x58: /* CLI */
if((HU_P & I_FLAG) && (HU_IRQlow & MDFN_IQIRQ1))
{
uint8 moo_op = RdAtPC();
if((moo_op == 0xAC || moo_op == 0xAD || moo_op == 0xAE) &&
((RdOp(GetRealPC() + 1) & 0x3) == 0) && ((RdOp(GetRealPC() + 2) & 0xFC) == 0))
{
HU_IRQlow |= 0x200;
//puts("CLI/LDA madness!");
}
}
HU_P&=~I_FLAG;
break;
case 0xB8: /* CLV */
HU_P&=~V_FLAG;
break;
case 0x38: /* SEC */
HU_P|=C_FLAG;
break;
case 0xF8: /* SED */
HU_P|=D_FLAG;
break;
case 0x78: /* SEI */
HU_P|=I_FLAG;
break;
case 0xEA: /* NOP */
break;
case 0x0A: RMW_A(ASL);
case 0x06: RMW_ZP(ASL);
case 0x16: RMW_ZPX(ASL);
case 0x0E: RMW_AB(ASL);
case 0x1E: RMW_ABX(ASL);
case 0x3A: RMW_A(DEC);
case 0xC6: RMW_ZP(DEC);
case 0xD6: RMW_ZPX(DEC);
case 0xCE: RMW_AB(DEC);
case 0xDE: RMW_ABX(DEC);
case 0x1A: RMW_A(INC); // 65C02
case 0xE6: RMW_ZP(INC);
case 0xF6: RMW_ZPX(INC);
case 0xEE: RMW_AB(INC);
case 0xFE: RMW_ABX(INC);
case 0x4A: RMW_A(LSR);
case 0x46: RMW_ZP(LSR);
case 0x56: RMW_ZPX(LSR);
case 0x4E: RMW_AB(LSR);
case 0x5E: RMW_ABX(LSR);
case 0x2A: RMW_A(ROL);
case 0x26: RMW_ZP(ROL);
case 0x36: RMW_ZPX(ROL);
case 0x2E: RMW_AB(ROL);
case 0x3E: RMW_ABX(ROL);
case 0x6A: RMW_A(ROR);
case 0x66: RMW_ZP(ROR);
case 0x76: RMW_ZPX(ROR);
case 0x6E: RMW_AB(ROR);
case 0x7E: RMW_ABX(ROR);
case 0x69: LD_IM(ADC);
case 0x65: LD_ZP(ADC);
case 0x75: LD_ZPX(ADC);
case 0x6D: LD_AB(ADC);
case 0x7D: LD_ABX(ADC);
case 0x79: LD_ABY(ADC);
case 0x72: LD_IND(ADC);
case 0x61: LD_IX(ADC);
case 0x71: LD_IY(ADC);
case 0x29: LD_IM(AND);
case 0x25: LD_ZP(AND);
case 0x35: LD_ZPX(AND);
case 0x2D: LD_AB(AND);
case 0x3D: LD_ABX(AND);
case 0x39: LD_ABY(AND);
case 0x32: LD_IND(AND);
case 0x21: LD_IX(AND);
case 0x31: LD_IY(AND);
case 0x89: LD_IM(BIT);
case 0x24: LD_ZP(BIT);
case 0x34: LD_ZPX(BIT);
case 0x2C: LD_AB(BIT);
case 0x3C: LD_ABX(BIT);
case 0xC9: LD_IM(CMP);
case 0xC5: LD_ZP(CMP);
case 0xD5: LD_ZPX(CMP);
case 0xCD: LD_AB(CMP);
case 0xDD: LD_ABX(CMP);
case 0xD9: LD_ABY(CMP);
case 0xD2: LD_IND(CMP);
case 0xC1: LD_IX(CMP);
case 0xD1: LD_IY(CMP);
case 0xE0: LD_IM(CPX);
case 0xE4: LD_ZP(CPX);
case 0xEC: LD_AB(CPX);
case 0xC0: LD_IM(CPY);
case 0xC4: LD_ZP(CPY);
case 0xCC: LD_AB(CPY);
case 0x49: LD_IM(EOR);
case 0x45: LD_ZP(EOR);
case 0x55: LD_ZPX(EOR);
case 0x4D: LD_AB(EOR);
case 0x5D: LD_ABX(EOR);
case 0x59: LD_ABY(EOR);
case 0x52: LD_IND(EOR);
case 0x41: LD_IX(EOR);
case 0x51: LD_IY(EOR);
case 0xA9: LD_IM(LDA);
case 0xA5: LD_ZP(LDA);
case 0xB5: LD_ZPX(LDA);
case 0xAD: LD_AB(LDA);
case 0xBD: LD_ABX(LDA);
case 0xB9: LD_ABY(LDA);
case 0xB2: LD_IND(LDA);
case 0xA1: LD_IX(LDA);
case 0xB1: LD_IY(LDA);
case 0xA2: LD_IM(LDX);
case 0xA6: LD_ZP(LDX);
case 0xB6: LD_ZPY(LDX);
case 0xAE: LD_AB(LDX);
case 0xBE: LD_ABY(LDX);
case 0xA0: LD_IM(LDY);
case 0xA4: LD_ZP(LDY);
case 0xB4: LD_ZPX(LDY);
case 0xAC: LD_AB(LDY);
case 0xBC: LD_ABX(LDY);
case 0x09: LD_IM(ORA);
case 0x05: LD_ZP(ORA);
case 0x15: LD_ZPX(ORA);
case 0x0D: LD_AB(ORA);
case 0x1D: LD_ABX(ORA);
case 0x19: LD_ABY(ORA);
case 0x12: LD_IND(ORA);
case 0x01: LD_IX(ORA);
case 0x11: LD_IY(ORA);
case 0xE9: LD_IM(SBC);
case 0xE5: LD_ZP(SBC);
case 0xF5: LD_ZPX(SBC);
case 0xED: LD_AB(SBC);
case 0xFD: LD_ABX(SBC);
case 0xF9: LD_ABY(SBC);
case 0xF2: LD_IND(SBC);
case 0xE1: LD_IX(SBC);
case 0xF1: LD_IY(SBC);
case 0x85: ST_ZP(HU_A);
case 0x95: ST_ZPX(HU_A);
case 0x8D: ST_AB(HU_A);
case 0x9D: ST_ABX(HU_A);
case 0x99: ST_ABY(HU_A);
case 0x92: ST_IND(HU_A);
case 0x81: ST_IX(HU_A);
case 0x91: ST_IY(HU_A);
case 0x86: ST_ZP(HU_X);
case 0x96: ST_ZPY(HU_X);
case 0x8E: ST_AB(HU_X);
case 0x84: ST_ZP(HU_Y);
case 0x94: ST_ZPX(HU_Y);
case 0x8C: ST_AB(HU_Y);
/* BBRi */
case 0x0F: LD_ZP(BBRi(0));
case 0x1F: LD_ZP(BBRi(1));
case 0x2F: LD_ZP(BBRi(2));
case 0x3F: LD_ZP(BBRi(3));
case 0x4F: LD_ZP(BBRi(4));
case 0x5F: LD_ZP(BBRi(5));
case 0x6F: LD_ZP(BBRi(6));
case 0x7F: LD_ZP(BBRi(7));
/* BBSi */
case 0x8F: LD_ZP(BBSi(0));
case 0x9F: LD_ZP(BBSi(1));
case 0xAF: LD_ZP(BBSi(2));
case 0xBF: LD_ZP(BBSi(3));
case 0xCF: LD_ZP(BBSi(4));
case 0xDF: LD_ZP(BBSi(5));
case 0xEF: LD_ZP(BBSi(6));
case 0xFF: LD_ZP(BBSi(7));
/* BRA */
case 0x80: BRA; break;
/* BSR */
case 0x44:
{
PUSH_PC();
BRA;
}
break;
/* BCC */
case 0x90: JR(!(HU_P&C_FLAG)); break;
/* BCS */
case 0xB0: JR(HU_P&C_FLAG); break;
/* BVC */
case 0x50: JR(!(HU_P&V_FLAG)); break;
/* BVS */
case 0x70: JR(HU_P&V_FLAG); break;
#ifdef HUC6280_LAZY_FLAGS
/* BEQ */
case 0xF0: JR(!(HU_ZNFlags & 0xFF)); break;
/* BNE */
case 0xD0: JR((HU_ZNFlags & 0xFF)); break;
/* BMI */
case 0x30: JR((HU_ZNFlags & 0x80000000)); break;
/* BPL */
case 0x10: JR(!(HU_ZNFlags & 0x80000000)); break;
#else
/* BEQ */
case 0xF0: JR(HU_P&Z_FLAG); break;
/* BNE */
case 0xD0: JR(!(HU_P&Z_FLAG)); break;
/* BMI */
case 0x30: JR(HU_P&N_FLAG); break;
/* BPL */
case 0x10: JR(!(HU_P&N_FLAG)); break;
#endif
// RMB 65SC02
case 0x07: RMW_ZP(RMB(0));
case 0x17: RMW_ZP(RMB(1));
case 0x27: RMW_ZP(RMB(2));
case 0x37: RMW_ZP(RMB(3));
case 0x47: RMW_ZP(RMB(4));
case 0x57: RMW_ZP(RMB(5));
case 0x67: RMW_ZP(RMB(6));
case 0x77: RMW_ZP(RMB(7));
// SMB 65SC02
case 0x87: RMW_ZP(SMB(0));
case 0x97: RMW_ZP(SMB(1));
case 0xa7: RMW_ZP(SMB(2));
case 0xb7: RMW_ZP(SMB(3));
case 0xc7: RMW_ZP(SMB(4));
case 0xd7: RMW_ZP(SMB(5));
case 0xe7: RMW_ZP(SMB(6));
case 0xf7: RMW_ZP(SMB(7));
// STZ 65C02
case 0x64: ST_ZP(0);
case 0x74: ST_ZPX(0);
case 0x9C: ST_AB(0);
case 0x9E: ST_ABX(0);
// TRB 65SC02
case 0x14: RMW_ZP(TRB);
case 0x1C: RMW_AB(TRB);
// TSB 65SC02
case 0x04: RMW_ZP(TSB);
case 0x0C: RMW_AB(TSB);
// TST
case 0x83: { uint8 zoomhack=RdAtPC(); IncPC(); LD_ZP(TST); }
case 0xA3: { uint8 zoomhack=RdAtPC(); IncPC(); LD_ZPX(TST); }
case 0x93: { uint8 zoomhack=RdAtPC(); IncPC(); LD_AB(TST); }
case 0xB3: { uint8 zoomhack=RdAtPC(); IncPC(); LD_ABX(TST); }
case 0x22: // SAX(amaphone!)
{
uint8 tmp = HU_X;
HU_X = HU_A;
HU_A = tmp;
}
break;
case 0x42: // SAY(what?)
{
uint8 tmp = HU_Y;
HU_Y = HU_A;
HU_A = tmp;
}
break;
case 0x02: // SXY
{
uint8 tmp = HU_X;
HU_X = HU_Y;
HU_Y = tmp;
}
break;
case 0x73: // TII
LD_BMT(BMT_TII);
case 0xC3: // TDD
LD_BMT(BMT_TDD);
case 0xD3: // TIN
LD_BMT(BMT_TIN);
case 0xE3: // TIA
LD_BMT(BMT_TIA);
case 0xF3: // TAI
LD_BMT(BMT_TAI);
case 0x43: // TMAi
LD_IM(TMA);
case 0x53: // TAMi
LD_IM(TAM);
case 0x03: // ST0
LD_IM(ST0);
case 0x13: // ST1
LD_IM(ST1);
case 0x23: // ST2
LD_IM(ST2);
case 0xF4: /* SET */
{
// AND, EOR, ORA, ADC
uint8 Abackup = HU_A;
ADDCYC(3);
HU_A = HU_Page1[HU_X]; //PAGE1_R[HU_X];
switch(RdAtPC())
{
default: //puts("Bad SET");
break;
case 0x69: IncPC(); LD_IM(ADC);
case 0x65: IncPC(); LD_ZP(ADC);
case 0x75: IncPC(); LD_ZPX(ADC);
case 0x6D: IncPC(); LD_AB(ADC);
case 0x7D: IncPC(); LD_ABX(ADC);
case 0x79: IncPC(); LD_ABY(ADC);
case 0x72: IncPC(); LD_IND(ADC);
case 0x61: IncPC(); LD_IX(ADC);
case 0x71: IncPC(); LD_IY(ADC);
case 0x29: IncPC(); LD_IM(AND);
case 0x25: IncPC(); LD_ZP(AND);
case 0x35: IncPC(); LD_ZPX(AND);
case 0x2D: IncPC(); LD_AB(AND);
case 0x3D: IncPC(); LD_ABX(AND);
case 0x39: IncPC(); LD_ABY(AND);
case 0x32: IncPC(); LD_IND(AND);
case 0x21: IncPC(); LD_IX(AND);
case 0x31: IncPC(); LD_IY(AND);
case 0x49: IncPC(); LD_IM(EOR);
case 0x45: IncPC(); LD_ZP(EOR);
case 0x55: IncPC(); LD_ZPX(EOR);
case 0x4D: IncPC(); LD_AB(EOR);
case 0x5D: IncPC(); LD_ABX(EOR);
case 0x59: IncPC(); LD_ABY(EOR);
case 0x52: IncPC(); LD_IND(EOR);
case 0x41: IncPC(); LD_IX(EOR);
case 0x51: IncPC(); LD_IY(EOR);
case 0x09: IncPC(); LD_IM(ORA);
case 0x05: IncPC(); LD_ZP(ORA);
case 0x15: IncPC(); LD_ZPX(ORA);
case 0x0D: IncPC(); LD_AB(ORA);
case 0x1D: IncPC(); LD_ABX(ORA);
case 0x19: IncPC(); LD_ABY(ORA);
case 0x12: IncPC(); LD_IND(ORA);
case 0x01: IncPC(); LD_IX(ORA);
case 0x11: IncPC(); LD_IY(ORA);
}
HU_Page1[HU_X] /*PAGE1_W[HU_X]*/ = HU_A;
HU_A = Abackup;
}
break;
case 0xFC:
{
int32 ec_tmp;
ec_tmp = next_event - HuCPU.timestamp;
if(ec_tmp > 0)
{
ADDCYC(ec_tmp);
}
}
break;
default: MDFN_printf("Bad %02x at $%04x\n", b1, GetRealPC());
break;

View File

@ -0,0 +1,390 @@
/* 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 "pce.h"
#include "input.h"
#include "huc.h"
#include "input/gamepad.h"
#include "input/mouse.h"
#include "input/tsushinkb.h"
#include "../include/trio/trio.h"
#ifdef _WIN32
#include "../libretro/msvc_compat.h"
#endif
enum
{
PCEINPUT_NONE = 0,
PCEINPUT_GAMEPAD = 1,
PCEINPUT_MOUSE = 2,
PCEINPUT_TSUSHINKB = 3,
};
//PCE_Input_Device::PCE_Input_Device(int which)
//{
//
//}
PCE_Input_Device::~PCE_Input_Device()
{
}
void PCE_Input_Device::Power(int32 timestamp)
{
}
void PCE_Input_Device::AdjustTS(int32 delta)
{
}
void PCE_Input_Device::Write(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR)
{
}
uint8 PCE_Input_Device::Read(int32 timestamp)
{
return(0xF);
}
void PCE_Input_Device::Update(const void *data)
{
}
int PCE_Input_Device::StateAction(StateMem *sm, int load, int data_only, const char *section_name)
{
return(1);
}
static PCE_Input_Device *devices[5] = { NULL };
static bool MultiTapEnabled = TRUE;
static int InputTypes[5] = { 0 };
static uint8 *data_ptr[5];
static bool SEL, CLR;
static uint8 read_index = 0;
static void RemakeDevices(int which = -1)
{
int s = 0;
int e = 5;
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 PCEINPUT_NONE: break;
case PCEINPUT_GAMEPAD: devices[i] = PCEINPUT_MakeGamepad(i); break;
case PCEINPUT_MOUSE: devices[i] = PCEINPUT_MakeMouse(); break;
case PCEINPUT_TSUSHINKB: devices[i] = PCEINPUT_MakeTsushinKB(); break;
}
}
}
static void SyncSettings(void);
void PCEINPUT_SettingChanged(const char *name)
{
SyncSettings();
}
void PCEINPUT_Init(void)
{
SyncSettings();
RemakeDevices();
}
void PCEINPUT_SetInput(int port, const char *type, void *ptr)
{
assert(port < 5);
if(!strcasecmp(type, "gamepad"))
InputTypes[port] = PCEINPUT_GAMEPAD;
else if(!strcasecmp(type, "mouse"))
InputTypes[port] = PCEINPUT_MOUSE;
else if(!strcasecmp(type, "tsushinkb"))
InputTypes[port] = PCEINPUT_TSUSHINKB;
else
InputTypes[port] = PCEINPUT_NONE;
data_ptr[port] = (uint8 *)ptr;
RemakeDevices(port);
}
void INPUT_Frame(void)
{
for(int i = 0; i < 5; i++)
if(devices[i])
devices[i]->Update(data_ptr[i]);
}
void INPUT_FixTS(int32 timestamp)
{
for(int i = 0; i < 5; i++)
if(devices[i])
devices[i]->AdjustTS(-timestamp);
}
static INLINE uint8 RealPortRead(int32 timestamp, int which)
{
uint8 ret = 0xF;
//printf("RealInputRead: %d %d\n", which, timestamp);
if(devices[which])
ret = devices[which]->Read(timestamp);
return(ret);
}
static INLINE void RealPortWrite(int32 timestamp, int which, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR)
{
if(devices[which])
devices[which]->Write(timestamp, old_SEL, new_SEL, old_CLR, new_CLR);
}
static INLINE uint8 MultiTapRead(int32 timestamp)
{
uint8 ret = 0xF;
if(read_index > 4)
ret = 0;
else
ret = RealPortRead(timestamp, read_index);
return(ret);
}
static INLINE void MultiTapWrite(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR)
{
for(int i = 0; i < 5; i++)
RealPortWrite(timestamp, i, old_SEL, new_SEL, old_CLR, new_CLR);
// SEL held high, CLR transitions from 0->1, reset counter.
// Scratch that, only check if SEL is high on the write that changes CLR from 0 to 1, to fix "Strip Fighter".
if(/*old_SEL &&*/ new_SEL && !old_CLR && new_CLR)
{
//puts("Reset read index");
read_index = 0;
}
// CLR held low, SEL transitions from 0->1, increment counter.
else if(!old_CLR && !new_CLR && !old_SEL && new_SEL)
{
//puts("Increment read index");
if(read_index < 255)
read_index++;
}
}
uint8 INPUT_Read(int32 timestamp, unsigned int A)
{
uint8 ret;
//{
// extern VCE *vce;
// printf("Input Read: %04x, %d\n", A, vce->GetScanlineNo());
//}
if(MultiTapEnabled && InputTypes[0] != PCEINPUT_TSUSHINKB)
ret = MultiTapRead(timestamp);
else
ret = RealPortRead(timestamp, 0);
//printf("Input read: %04x, %02x\n",A,ret);
if(!PCE_IsCD)
ret |= 0x80; // Set when CDROM is not attached
//ret |= 0x40; // PC Engine if set, TG16 if clear. Let's leave it clear, PC Engine games don't seem to mind if it's clear, but TG16 games barf if it's set.
ret |= 0x30; // Always-set?
return(ret);
}
void INPUT_Write(int32 timestamp, unsigned int A, uint8 V)
{
//printf("Input Write: %04x, %02x\n", A, V);
bool new_SEL = V & 0x1;
bool new_CLR = V & 0x2;
if(MultiTapEnabled)
MultiTapWrite(timestamp, SEL, new_SEL, CLR, new_CLR);
else
RealPortWrite(timestamp, 0, SEL, new_SEL, CLR, new_CLR);
SEL = new_SEL;
CLR = new_CLR;
}
void PCEINPUT_Power(int32 timestamp)
{
read_index = 0;
SEL = 0;
CLR = 0;
for(int i = 0; i < 5; i++)
if(devices[i])
devices[i]->Power(timestamp);
}
int INPUT_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFVAR(SEL),
SFVAR(CLR),
SFVAR(read_index),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "JOY");
for(int i = 0; i < 5; i++)
{
if(devices[i])
{
char sn[8];
trio_snprintf(sn, 8, "INP%d", i);
ret &= devices[i]->StateAction(sm, load, data_only, sn);
}
}
return(ret);
}
// If we add more devices to these arrays before "gamepad", REMEMBER TO UPDATE the hackish array indexing in the SyncSettings() function
// below.
static InputDeviceInfoStruct InputDeviceInfo[] =
{
// None
{
"none",
"none",
NULL,
NULL,
0,
NULL
},
// Gamepad
{
"gamepad",
"Gamepad",
NULL,
NULL,
sizeof(PCE_GamepadIDII) / sizeof(InputDeviceInputInfoStruct),
PCE_GamepadIDII,
},
// Mouse
{
"mouse",
"Mouse",
NULL,
NULL,
sizeof(PCE_MouseIDII) / sizeof(InputDeviceInputInfoStruct),
PCE_MouseIDII,
},
};
static InputDeviceInfoStruct InputDeviceInfoPort1[] =
{
// None
{
"none",
"none",
NULL,
NULL,
0,
NULL
},
// Gamepad
{
"gamepad",
"Gamepad",
NULL,
NULL,
sizeof(PCE_GamepadIDII) / sizeof(InputDeviceInputInfoStruct),
PCE_GamepadIDII,
},
// Mouse
{
"mouse",
"Mouse",
NULL,
NULL,
sizeof(PCE_MouseIDII) / sizeof(InputDeviceInputInfoStruct),
PCE_MouseIDII,
},
// Tsushin Keyboard
{
"tsushinkb",
"Tsushin Keyboard",
NULL,
NULL,
sizeof(PCE_TsushinKBIDII) / sizeof(InputDeviceInputInfoStruct),
PCE_TsushinKBIDII,
},
};
static const InputPortInfoStruct PortInfo[] =
{
{ "port1", "Port 1", sizeof(InputDeviceInfoPort1) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPort1, "gamepad" },
{ "port2", "Port 2", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
{ "port3", "Port 3", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
{ "port4", "Port 4", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
{ "port5", "Port 5", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
};
InputInfoStruct PCEInputInfo =
{
sizeof(PortInfo) / sizeof(InputPortInfoStruct),
PortInfo
};
static void SyncSettings(void)
{
MDFNGameInfo->mouse_sensitivity = MDFN_GetSettingF("pce_fast.mouse_sensitivity");
InputDeviceInfo[1].IDII = MDFN_GetSettingB("pce_fast.disable_softreset") ? PCE_GamepadIDII_DSR : PCE_GamepadIDII;
MultiTapEnabled = MDFN_GetSettingB("pce_fast.input.multitap");
}

View File

@ -0,0 +1,28 @@
#ifndef __PCE_INPUT_H
#define __PCE_INPUT_H
class PCE_Input_Device
{
public:
// PCE_Input_Device(int which); // "which" is advisory and only should be used in status messages.
virtual ~PCE_Input_Device();
virtual void AdjustTS(int32 delta);
virtual void Write(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR);
virtual uint8 Read(int32 timestamp);
virtual void Power(int32 timestamp);
virtual void Update(const void *data);
virtual int StateAction(StateMem *sm, int load, int data_only, const char *section_name);
};
void PCEINPUT_Power(int32 timestamp);
void PCEINPUT_Init(void);
void PCEINPUT_SettingChanged(const char *name);
void PCEINPUT_SetInput(int port, const char *type, void *ptr);
uint8 INPUT_Read(int32 timestamp, unsigned int A);
void INPUT_Write(int32 timestamp, unsigned int A, uint8 V);
void INPUT_Frame(void);
int INPUT_StateAction(StateMem *sm, int load, int data_only);
extern InputInfoStruct PCEInputInfo;
void INPUT_FixTS(int32 timestamp);
#endif

View File

@ -0,0 +1,157 @@
/* 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 "../pce.h"
#include "../input.h"
#include "gamepad.h"
class PCE_Input_Gamepad : public PCE_Input_Device
{
public:
PCE_Input_Gamepad(int which);
virtual void Power(int32 timestamp);
virtual void Write(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR);
virtual uint8 Read(int32 timestamp);
virtual void Update(const void *data);
virtual int StateAction(StateMem *sm, int load, int data_only, const char *section_name);
private:
bool SEL, CLR;
uint16 buttons;
bool AVPad6Which;
bool AVPad6Enabled;
int which_this;
};
PCE_Input_Gamepad::PCE_Input_Gamepad(int which)
{
which_this = which;
Power(0); // FIXME?
}
void PCE_Input_Gamepad::Power(int32 timestamp)
{
SEL = 0;
CLR = 0;
buttons = 0;
AVPad6Which = 0;
AVPad6Enabled = 0;
}
void PCE_Input_Gamepad::Update(const void *data)
{
uint16 new_data = MDFN_de16lsb((uint8 *)data);
if((new_data & 0x1000) && !(buttons & 0x1000))
{
AVPad6Enabled = !AVPad6Enabled;
//MDFN_DispMessage("%d-button mode selected for pad %d", AVPad6Enabled ? 6 : 2, which_this + 1);
}
buttons = new_data;
}
uint8 PCE_Input_Gamepad::Read(int32 timestamp)
{
uint8 ret = 0xF;
if(AVPad6Which && AVPad6Enabled)
{
if(SEL)
ret ^= 0xF;
else
ret ^= (buttons >> 8) & 0x0F;
}
else
{
if(SEL)
ret ^= (buttons >> 4) & 0x0F;
else
ret ^= buttons & 0x0F;
}
//if(CLR)
// ret = 0;
return(ret);
}
void PCE_Input_Gamepad::Write(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR)
{
SEL = new_SEL;
CLR = new_CLR;
//if(old_SEL && new_SEL && old_CLR && !new_CLR)
if(!old_SEL && new_SEL)
AVPad6Which = !AVPad6Which;
}
int PCE_Input_Gamepad::StateAction(StateMem *sm, int load, int data_only, const char *section_name)
{
SFORMAT StateRegs[] =
{
SFVAR(SEL),
SFVAR(CLR),
SFVAR(buttons),
SFVAR(AVPad6Which),
SFVAR(AVPad6Enabled),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
return(ret);
}
// GamepadIDII and GamepadIDII_DSR must be EXACTLY the same except for the RUN+SELECT exclusion in the latter.
const InputDeviceInputInfoStruct PCE_GamepadIDII[0xD] =
{
{ "i", "I", 12, IDIT_BUTTON_CAN_RAPID, NULL },
{ "ii", "II", 11, IDIT_BUTTON_CAN_RAPID, NULL },
{ "select", "SELECT", 4, IDIT_BUTTON, NULL },
{ "run", "RUN", 5, IDIT_BUTTON, NULL },
{ "up", "UP ↑", 0, IDIT_BUTTON, "down" },
{ "right", "RIGHT →", 3, IDIT_BUTTON, "left" },
{ "down", "DOWN ↓", 1, IDIT_BUTTON, "up" },
{ "left", "LEFT ←", 2, IDIT_BUTTON, "right" },
{ "iii", "III", 10, IDIT_BUTTON, NULL },
{ "iv", "IV", 7, IDIT_BUTTON, NULL },
{ "v", "V", 8, IDIT_BUTTON, NULL },
{ "vi", "VI", 9, IDIT_BUTTON, NULL },
{ "mode_select", "2/6 Mode Select", 6, IDIT_BUTTON, NULL },
};
const InputDeviceInputInfoStruct PCE_GamepadIDII_DSR[0xD] =
{
{ "i", "I", 12, IDIT_BUTTON_CAN_RAPID, NULL },
{ "ii", "II", 11, IDIT_BUTTON_CAN_RAPID, NULL },
{ "select", "SELECT", 4, IDIT_BUTTON, "run" },
{ "run", "RUN", 5, IDIT_BUTTON, "select" },
{ "up", "UP ↑", 0, IDIT_BUTTON, "down" },
{ "right", "RIGHT →", 3, IDIT_BUTTON, "left" },
{ "down", "DOWN ↓", 1, IDIT_BUTTON, "up" },
{ "left", "LEFT ←", 2, IDIT_BUTTON, "right" },
{ "iii", "III", 10, IDIT_BUTTON, NULL },
{ "iv", "IV", 7, IDIT_BUTTON, NULL },
{ "v", "V", 8, IDIT_BUTTON, NULL },
{ "vi", "VI", 9, IDIT_BUTTON, NULL },
{ "mode_select", "2/6 Mode Select", 6, IDIT_BUTTON, NULL },
};
PCE_Input_Device *PCEINPUT_MakeGamepad(int which)
{
return(new PCE_Input_Gamepad(which));
}

View File

@ -0,0 +1,9 @@
#ifndef __PCE_INPUT_GAMEPAD_H
#define __PCE_INPUT_GAMEPAD_H
extern const InputDeviceInputInfoStruct PCE_GamepadIDII[0xD];
extern const InputDeviceInputInfoStruct PCE_GamepadIDII_DSR[0xD];
PCE_Input_Device *PCEINPUT_MakeGamepad(int which);
#endif

View File

@ -0,0 +1,166 @@
/* 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 "../pce.h"
#include "../input.h"
#include "mouse.h"
class PCE_Input_Mouse : public PCE_Input_Device
{
public:
PCE_Input_Mouse();
virtual void Power(int32 timestamp);
virtual void AdjustTS(int32 delta);
virtual void Write(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR);
virtual uint8 Read(int32 timestamp);
virtual void Update(const void *data);
virtual int StateAction(StateMem *sm, int load, int data_only, const char *section_name);
private:
bool SEL, CLR;
int64 mouse_last_meow;
int32 mouse_x, mouse_y;
uint8 pce_mouse_button;
uint8 mouse_index;
uint16 mouse_shifter;
};
void PCE_Input_Mouse::Power(int32 timestamp)
{
SEL = CLR = 0;
mouse_last_meow = 0;
mouse_x = mouse_y = 0;
pce_mouse_button = 0;
mouse_index = 0;
mouse_shifter = 0;
}
PCE_Input_Mouse::PCE_Input_Mouse()
{
Power(0);
}
void PCE_Input_Mouse::Update(const void *data)
{
//puts("Frame");
uint8 *data_ptr = (uint8 *)data;
mouse_x += (int32)MDFN_de32lsb(data_ptr + 0);
mouse_y += (int32)MDFN_de32lsb(data_ptr + 4);
pce_mouse_button = *(uint8 *)(data_ptr + 8);
}
void PCE_Input_Mouse::AdjustTS(int32 delta)
{
//printf("Adjust: %d\n", delta);
mouse_last_meow += delta;
}
void PCE_Input_Mouse::Write(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR)
{
//printf("Write: %d old_SEL=%d, new_SEL=%d, old_CLR=%d, new_CLR=%d\n", timestamp, old_SEL, new_SEL, old_CLR, new_CLR);
if(!old_CLR && new_CLR)
{
//printf("%lld\n", (int64)timestamp - mouse_last_meow);
if(((int64)timestamp - mouse_last_meow) > 10000 * 3)
{
mouse_last_meow = timestamp;
int32 rel_x = (int32)((0-mouse_x));
int32 rel_y = (int32)((0-mouse_y));
if(rel_x < -127) rel_x = -127;
if(rel_x > 127) rel_x = 127;
if(rel_y < -127) rel_y = -127;
if(rel_y > 127) rel_y = 127;
mouse_shifter = ((rel_x & 0xF0) >> 4) | ((rel_x & 0x0F) << 4);
mouse_shifter |= (((rel_y & 0xF0) >> 4) | ((rel_y & 0x0F) << 4)) << 8;
mouse_x += (int32)(rel_x);
mouse_y += (int32)(rel_y);
//printf("Latch: %d %d, %04x\n", rel_x, rel_y, mouse_shifter);
}
else
{
//puts("Shift");
mouse_shifter >>= 4;
}
}
SEL = new_SEL;
CLR = new_CLR;
}
uint8 PCE_Input_Mouse::Read(int32 timestamp)
{
uint8 ret = 0xF;
//printf("Read: %d\n", timestamp);
if(SEL)
{
ret = (mouse_shifter & 0xF);
//printf("Read: %02x\n", ret);
}
else
{
ret ^= pce_mouse_button & 0xF;
}
return(ret);
}
int PCE_Input_Mouse::StateAction(StateMem *sm, int load, int data_only, const char *section_name)
{
SFORMAT StateRegs[] =
{
SFVAR(SEL),
SFVAR(CLR),
SFVAR(mouse_last_meow),
SFVAR(mouse_x),
SFVAR(mouse_y),
SFVAR(pce_mouse_button),
SFVAR(mouse_index),
SFVAR(mouse_shifter),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
return(ret);
}
const InputDeviceInputInfoStruct PCE_MouseIDII[0x6] =
{
{ "x_axis", "X Axis", -1, IDIT_X_AXIS_REL },
{ "y_axis", "Y Axis", -1, IDIT_Y_AXIS_REL },
{ "right", "Right Button", 3, IDIT_BUTTON, NULL },
{ "left", "Left Button", 2, IDIT_BUTTON, NULL },
{ "select", "SELECT", 0, IDIT_BUTTON, NULL },
{ "run", "RUN", 1, IDIT_BUTTON, NULL },
};
PCE_Input_Device *PCEINPUT_MakeMouse(void)
{
return(new PCE_Input_Mouse());
}

View File

@ -0,0 +1,8 @@
#ifndef __PCE_INPUT_MOUSE_H
#define __PCE_INPUT_MOUSE_H
extern const InputDeviceInputInfoStruct PCE_MouseIDII[0x6];
PCE_Input_Device *PCEINPUT_MakeMouse(void);
#endif

View File

@ -0,0 +1,299 @@
/* 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 "../pce.h"
#include "../input.h"
#include "tsushinkb.h"
class PCE_Input_TsushinKB : public PCE_Input_Device
{
public:
PCE_Input_TsushinKB();
virtual void Power(int32 timestamp);
virtual void Write(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR);
virtual uint8 Read(int32 timestamp);
virtual void Update(const void *data);
virtual int StateAction(StateMem *sm, int load, int data_only, const char *section_name);
private:
bool SEL, CLR;
uint8 TsuKBState[16];
uint8 TsuKBLatch[16 + 2 + 1];
uint32 TsuKBIndex;
bool last_capslock;
};
void PCE_Input_TsushinKB::Power(int32 timestamp)
{
SEL = CLR = 0;
memset(TsuKBState, 0, sizeof(TsuKBState));
memset(TsuKBLatch, 0, sizeof(TsuKBLatch));
TsuKBIndex = 0;
last_capslock = 0;
}
PCE_Input_TsushinKB::PCE_Input_TsushinKB()
{
Power(0);
}
void PCE_Input_TsushinKB::Update(const void *data)
{
uint8 *data_ptr = (uint8 *)data;
bool capslock = TsuKBState[0xE] & 0x10;
bool new_capslock = data_ptr[0xE] & 0x10;
if(!last_capslock && new_capslock)
capslock ^= 1;
for(int i = 0; i < 16; i++)
{
TsuKBState[i] = data_ptr[i];
}
TsuKBState[0xE] = (TsuKBState[0xE] & ~0x10) | (capslock ? 0x10 : 0x00);
last_capslock = new_capslock;
}
uint8 PCE_Input_TsushinKB::Read(int32 timestamp)
{
uint8 ret;
ret = ((TsuKBLatch[TsuKBIndex] >> (SEL * 4)) & 0xF);
return(ret);
}
void PCE_Input_TsushinKB::Write(int32 timestamp, bool old_SEL, bool new_SEL, bool old_CLR, bool new_CLR)
{
SEL = new_SEL;
CLR = new_CLR;
//printf("Write: %d %d %d %d\n", old_SEL, new_SEL, old_CLR, new_CLR);
if(!old_CLR && new_CLR)
{
TsuKBLatch[0] = 0x02;
for(int i = 0; i < 16; i++)
TsuKBLatch[i + 1] = TsuKBState[i] ^ 0xFF;
TsuKBLatch[17] = 0x02;
TsuKBIndex = 0;
//puts("Latched");
}
else if(!old_SEL && new_SEL)
{
TsuKBIndex = (TsuKBIndex + 1) % 18;
if(!TsuKBIndex)
{
for(int i = 0; i < 16; i++)
TsuKBLatch[i + 1] = TsuKBState[i] ^ 0xFF;
}
}
}
int PCE_Input_TsushinKB::StateAction(StateMem *sm, int load, int data_only, const char *section_name)
{
SFORMAT StateRegs[] =
{
SFVAR(SEL),
SFVAR(CLR),
SFARRAY(TsuKBState, sizeof(TsuKBState)),
SFARRAY(TsuKBLatch, sizeof(TsuKBLatch)),
SFVAR(TsuKBIndex),
SFVAR(last_capslock),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
return(ret);
}
const InputDeviceInputInfoStruct PCE_TsushinKBIDII[0x80] =
{
// 0 - DONE!
{ "kp_0", "Keypad 0", 0, IDIT_BUTTON },
{ "kp_1", "Keypad 1", 0, IDIT_BUTTON },
{ "kp_2", "Keypad 2", 0, IDIT_BUTTON },
{ "kp_3", "Keypad 3", 0, IDIT_BUTTON },
{ "kp_4", "Keypad 4", 0, IDIT_BUTTON },
{ "kp_5", "Keypad 5", 0, IDIT_BUTTON },
{ "kp_6", "Keypad 6", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 1 - DONE!
{ "kp_8", "Keypad 8", 0, IDIT_BUTTON },
{ "kp_9", "Keypad 9", 0, IDIT_BUTTON },
{ "kp_multiply", "Keypad *", 0, IDIT_BUTTON },
{ "kp_plus", "Keypad +", 0, IDIT_BUTTON },
{ "kp_equals", "Keypad =", 0, IDIT_BUTTON },
{ "kp_comma", "Keypad ,", 0, IDIT_BUTTON },
{ "kp_period", "Keypad .", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 2 - DONE!
{ "at", "@", 0, IDIT_BUTTON },
{ "a", "a", 0, IDIT_BUTTON },
{ "b", "b", 0, IDIT_BUTTON },
{ "c", "c", 0, IDIT_BUTTON },
{ "d", "d", 0, IDIT_BUTTON },
{ "e", "e", 0, IDIT_BUTTON },
{ "f", "f", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 3 - DONE!
{ "h", "h", 0, IDIT_BUTTON },
{ "i", "i", 0, IDIT_BUTTON },
{ "j", "j", 0, IDIT_BUTTON },
{ "k", "k", 0, IDIT_BUTTON },
{ "l", "l", 0, IDIT_BUTTON },
{ "m", "m", 0, IDIT_BUTTON },
{ "n", "n", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 4 - DONE!
{ "p", "p", 0, IDIT_BUTTON },
{ "q", "q", 0, IDIT_BUTTON },
{ "r", "r", 0, IDIT_BUTTON },
{ "s", "s", 0, IDIT_BUTTON },
{ "t", "t", 0, IDIT_BUTTON },
{ "u", "u", 0, IDIT_BUTTON },
{ "v", "v", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 5 - DONE!
{ "x", "x", 0, IDIT_BUTTON },
{ "y", "y", 0, IDIT_BUTTON },
{ "z", "z", 0, IDIT_BUTTON },
{ "left_bracket", "[", 0, IDIT_BUTTON },
{ "yen", "Yen", 0, IDIT_BUTTON },
{ "right_bracket", "]", 0, IDIT_BUTTON },
{ "caret", "^", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 6 - DONE!
{ "0", "0", 0, IDIT_BUTTON },
{ "1", "1", 0, IDIT_BUTTON },
{ "2", "2", 0, IDIT_BUTTON },
{ "3", "3", 0, IDIT_BUTTON },
{ "4", "4", 0, IDIT_BUTTON },
{ "5", "5", 0, IDIT_BUTTON },
{ "6", "6", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 7 - DONE!
{ "8", "8", 0, IDIT_BUTTON },
{ "9", "9", 0, IDIT_BUTTON },
{ "colon", ":", 0, IDIT_BUTTON },
{ "semicolon", ";", 0, IDIT_BUTTON },
{ "comma", ",", 0, IDIT_BUTTON },
{ "period", ".", 0, IDIT_BUTTON },
{ "slash", "/", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 8 - DONE enough
{ "clear", "clear", 0, IDIT_BUTTON },
{ "up", "up", 0, IDIT_BUTTON },
{ "right", "right", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON }, // Alternate backspace key on PC-88 keyboard??? { "unk80", "unknown", 0, IDIT_BUTTON },
{ "grph", "GRPH", 0, IDIT_BUTTON },
{ "kana", "カナ", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON }, // Alternate shift key on PC-88 keyboard??? { "unk83", "unknown", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 9 - DONE!
{ "stop", "STOP", 0, IDIT_BUTTON }, // Break / STOP
{ "f1", "F1", 0, IDIT_BUTTON },
{ "f2", "F2", 0, IDIT_BUTTON },
{ "f3", "F3", 0, IDIT_BUTTON },
{ "f4", "F4", 0, IDIT_BUTTON },
{ "f5", "F5", 0, IDIT_BUTTON },
{ "space", "space", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// A - DONE!
{ "tab", "Tab", 0, IDIT_BUTTON }, // Tab
{ "down", "down", 0, IDIT_BUTTON },
{ "left", "left", 0, IDIT_BUTTON },
{ "help", "Help", 0, IDIT_BUTTON }, // -624
{ "copy", "Copy", 0, IDIT_BUTTON }, // -623
{ "kp_minus", "Keypad Minus", 0, IDIT_BUTTON },
{ "kp_divide", "Keypad Divide", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// B - DONE(most likely)
{ "roll_down", "ROLL DOWN", 0, IDIT_BUTTON },
{ "roll_up", "ROLL UP", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON }, // { "unknownB2", "unknown", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON }, // { "unknownB3", "unknown", 0, IDIT_BUTTON },
{ "o", "o", 0, IDIT_BUTTON },
{ "underscore", "Underscore", 0, IDIT_BUTTON },
{ "g", "g", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// C - DONE!
{ "f6", "f6", 0, IDIT_BUTTON },
{ "f7", "f7", 0, IDIT_BUTTON },
{ "f8", "f8", 0, IDIT_BUTTON },
{ "f9", "f9", 0, IDIT_BUTTON },
{ "f10", "F10", 0, IDIT_BUTTON },
{ "backspace", "backspace", 0, IDIT_BUTTON },
{ "insert", "insert", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// D - DONE!
{ "convert", "変換", 0, IDIT_BUTTON }, // (-620) Begin marking entered text, and disable marking after pressing the
// end-of-block key.
{ "nonconvert", "決定", 0, IDIT_BUTTON }, // (-619) End text marking block
{ "pc", "PC", 0, IDIT_BUTTON }, // (-617) Selects between Rgana and Rkana. SHIFT+this key switches between
// latin and kana/gana mode?
{ "width", "変換", 0, IDIT_BUTTON }, // (-618) Chooses font width?
{ "ctrl", "CTRL/Control", 0, IDIT_BUTTON }, // CTRL
{ "kp_7", "Keypad 7", 0, IDIT_BUTTON },
{ "w", "w", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// E - DONE!
{ "return", "return", 0, IDIT_BUTTON }, // enter
{ "kp_enter", "Keypad Enter", 0, IDIT_BUTTON }, // enter
{ "left_shift", "Left Shift", 0, IDIT_BUTTON }, // Left Shift
{ "right_shift", "Right Shift", 0, IDIT_BUTTON }, // Right Shift
{ "caps_lock", "Caps Lock", 0, IDIT_BUTTON }, // Caps Lock(mechanically-locking...)
{ "delete", "Delete", 0, IDIT_BUTTON },
{ "escape", "Escape", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// F - DONE(most likely)
{ NULL, "empty", 0, IDIT_BUTTON }, // { "unknownF0", "unknown", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON }, // { "unknownF1", "unknown", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON }, // { "unknownF2", "unknown", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON }, // { "unknownF3", "unknown", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON }, // { "unknownF4", "unknown", 0, IDIT_BUTTON },
{ "minus", "Minus", 0, IDIT_BUTTON },
{ "7", "7", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
};
PCE_Input_Device *PCEINPUT_MakeTsushinKB(void)
{
return(new PCE_Input_TsushinKB());
}

View File

@ -0,0 +1,8 @@
#ifndef __PCE_INPUT_TSUSHINKB_H
#define __PCE_INPUT_TSUSHINKB_H
extern const InputDeviceInputInfoStruct PCE_TsushinKBIDII[0x80];
PCE_Input_Device *PCEINPUT_MakeTsushinKB(void);
#endif

View File

@ -0,0 +1,163 @@
A &= 0x1FFF;
unsigned val = ((A & 0x1C00) >> 8) | (A & 0x3);
switch(val)
{
case 0:
goto VDC_00;
case 1:
goto VDC_01;
case 2:
goto VDC_02;
case 3:
goto VDC_03;
case 4:
goto VCE_00;
case 5:
goto VCE_01;
case 6:
goto VCE_02;
case 7:
goto VCE_03;
case 8:
case 9:
case 10:
case 11:
goto PSG;
case 12:
goto TIMER_00;
case 13:
goto TIMER_01;
case 14:
goto TIMER_02;
case 15:
goto TIMER_03;
case 16:
goto INPUT_00;
case 17:
goto INPUT_01;
case 18:
goto INPUT_02;
case 19:
goto INPUT_03;
case 20:
goto IRQ_00;
case 21:
goto IRQ_01;
case 22:
goto IRQ_02;
case 23:
goto IRQ_03;
case 24:
case 25:
case 26:
case 27:
goto CDROM;
case 28:
case 29:
case 30:
case 31:
goto EXP;
}
#if IOREAD_SGX==1
VDC_00:
VDC_01:
VDC_02:
VDC_03: HuC6280_StealCycle();
return(VDC_Read(A&0x1F, TRUE));
#else
VDC_00:
HuC6280_StealCycle();
return(VDC_Read(0, FALSE));
VDC_01:
HuC6280_StealCycle();
return(VDC_Read(1, FALSE));
VDC_02:
HuC6280_StealCycle();
return(VDC_Read(2, FALSE));
VDC_03:
HuC6280_StealCycle();
return(VDC_Read(3, FALSE));
#endif
VCE_00:
VCE_01:
VCE_02:
VCE_03:
HuC6280_StealCycle();
return(VCE_Read(A));
PSG:
if(HuCPU.in_block_move)
return(0);
return(PCEIODataBuffer);
TIMER_00:
TIMER_01:
TIMER_02:
TIMER_03:
if(HuCPU.in_block_move)
return(0);
{
uint8 ret = HuC6280_TimerRead(A);
PCEIODataBuffer = ret;
return(ret);
}
INPUT_00:
INPUT_01:
INPUT_02:
INPUT_03:
if(HuCPU.in_block_move)
return(0);
{
uint8 ret = INPUT_Read(A, 0);
PCEIODataBuffer = ret;
return(ret);
}
IRQ_00:
IRQ_01:
IRQ_02:
IRQ_03:
if(HuCPU.in_block_move)
return(0);
{
uint8 ret = HuC6280_IRQStatusRead(A);
PCEIODataBuffer = ret;
return(ret);
}
CDROM:
if(IsTsushin)
return(PCE_TsushinRead(A));
if(!PCE_IsCD)
return(0xFF);
if((A & 0x1E00) == 0x1A00)
{
if(arcade_card)
return(arcade_card->Read(A & 0x1FFF));
else
return(0);
}
else
{
int32 next_cd_event;
return(PCECD_Read(HuCPU.timestamp * 3, A, next_cd_event));
}
EXP:
//printf("Meow: %08x, %02x:%04x\n", A, A >> 13, A & 0x1FFF);
return(0xFF);

View File

@ -0,0 +1,650 @@
/* 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 "pce.h"
#include "vdc.h"
#include "../hw_sound/pce_psg/pce_psg.h"
#include "input.h"
#include "huc.h"
#include "../cdrom/pcecd.h"
#include "../cdrom/scsicd.h"
#include "tsushin.h"
#include "../hw_misc/arcade_card/arcade_card.h"
#include "../mempatcher.h"
#include "../cdrom/cdromif.h"
#include "pce_huc6280.h"
#ifdef HAVE_CRC32
#include "../../scrc32.cpp"
#endif
#ifdef _WIN32
#include "../libretro/msvc_compat.h"
#endif
static PCE_PSG *psg = NULL;
extern ArcadeCard *arcade_card; // Bah, lousy globals.
static Blip_Buffer sbuf[2];
bool PCE_ACEnabled;
static bool IsSGX;
int pce_overclocked;
// Statically allocated for speed...or something.
uint8 ROMSpace[0x88 * 8192 + 8192]; // + 8192 for PC-as-pointer safety padding
uint8 BaseRAM[32768 + 8192]; // 8KB for PCE, 32KB for Super Grafx // + 8192 for PC-as-pointer safety padding
uint8 PCEIODataBuffer;
readfunc PCERead[0x100];
writefunc PCEWrite[0x100];
static DECLFR(PCEBusRead)
{
//printf("BUS Read: %02x %04x\n", A >> 13, A);
return(0xFF);
}
static DECLFW(PCENullWrite)
{
//printf("Null Write: %02x, %08x %02x\n", A >> 13, A, V);
}
static DECLFR(BaseRAMReadSGX)
{
return((BaseRAM - (0xF8 * 8192))[A]);
}
static DECLFW(BaseRAMWriteSGX)
{
(BaseRAM - (0xF8 * 8192))[A] = V;
}
static DECLFR(BaseRAMRead)
{
return((BaseRAM - (0xF8 * 8192))[A]);
}
static DECLFR(BaseRAMRead_Mirrored)
{
return(BaseRAM[A & 0x1FFF]);
}
static DECLFW(BaseRAMWrite)
{
(BaseRAM - (0xF8 * 8192))[A] = V;
}
static DECLFW(BaseRAMWrite_Mirrored)
{
BaseRAM[A & 0x1FFF] = V;
}
static DECLFR(IORead)
{
#define IOREAD_SGX 0
#include "ioread.inc"
#undef IOREAD_SGX
}
static DECLFR(IOReadSGX)
{
#define IOREAD_SGX 1
#include "ioread.inc"
#undef IOREAD_SGX
}
static DECLFW(IOWrite)
{
A &= 0x1FFF;
switch(A & 0x1c00)
{
case 0x0000: HuC6280_StealCycle();
VDC_Write(A, V);
break;
case 0x0400: HuC6280_StealCycle();
VCE_Write(A, V);
break;
case 0x0800: PCEIODataBuffer = V;
psg->Write(HuCPU.timestamp / pce_overclocked, A, V);
break;
case 0x0c00: PCEIODataBuffer = V;
HuC6280_TimerWrite(A, V);
break;
case 0x1000: PCEIODataBuffer = V; INPUT_Write(HuCPU.timestamp, A, V); break;
case 0x1400: PCEIODataBuffer = V; HuC6280_IRQStatusWrite(A, V); break;
case 0x1800: if(IsTsushin)
PCE_TsushinWrite(A, V);
if(!PCE_IsCD)
break;
if((A & 0x1E00) == 0x1A00)
{
if(arcade_card)
arcade_card->Write(A & 0x1FFF, V);
}
else
{
int32 dummy_ne;
dummy_ne = PCECD_Write(HuCPU.timestamp * 3, A, V);
}
break;
//case 0x1C00: break; // Expansion
//default: printf("Eep: %04x\n", A); break;
}
}
static void PCECDIRQCB(bool asserted)
{
if(asserted)
HuC6280_IRQBegin(MDFN_IQIRQ2);
else
HuC6280_IRQEnd(MDFN_IQIRQ2);
}
bool PCE_InitCD(void)
{
PCECD_Settings cd_settings;
memset(&cd_settings, 0, sizeof(PCECD_Settings));
cd_settings.CDDA_Volume = (double)MDFN_GetSettingUI("pce_fast.cddavolume") / 100;
cd_settings.CD_Speed = MDFN_GetSettingUI("pce_fast.cdspeed");
cd_settings.ADPCM_Volume = (double)MDFN_GetSettingUI("pce_fast.adpcmvolume") / 100;
cd_settings.ADPCM_LPF = MDFN_GetSettingB("pce_fast.adpcmlp");
if(cd_settings.CDDA_Volume != 1.0)
MDFN_printf(_("CD-DA Volume: %d%%\n"), (int)(100 * cd_settings.CDDA_Volume));
if(cd_settings.ADPCM_Volume != 1.0)
MDFN_printf(_("ADPCM Volume: %d%%\n"), (int)(100 * cd_settings.ADPCM_Volume));
return(PCECD_Init(&cd_settings, PCECDIRQCB, PCE_MASTER_CLOCK, pce_overclocked, &sbuf[0], &sbuf[1]));
}
static int LoadCommon(void);
static void LoadCommonPre(void);
static bool TestMagic(const char *name, MDFNFILE *fp)
{
if(memcmp(fp->f_data, "HESM", 4) && strcasecmp(fp->f_ext, "pce") && strcasecmp(fp->f_ext, "sgx"))
return(FALSE);
return(TRUE);
}
static int Load(const char *name, MDFNFILE *fp)
{
uint32 headerlen = 0;
uint32 r_size;
IsSGX = 0;
LoadCommonPre();
{
if(fp->f_size & 0x200) // 512 byte header!
headerlen = 512;
}
r_size = fp->f_size - headerlen;
if(r_size > 4096 * 1024) r_size = 4096 * 1024;
for(int x = 0; x < 0x100; x++)
{
PCERead[x] = PCEBusRead;
PCEWrite[x] = PCENullWrite;
}
uint32 crc = crc32(0, fp->f_data + headerlen, fp->f_size - headerlen);
HuCLoad(fp->f_data + headerlen, fp->f_size - headerlen, crc);
if(!strcasecmp(fp->f_ext, "sgx"))
IsSGX = TRUE;
if(fp->f_size >= 8192 && !memcmp(fp->f_data + headerlen, "DARIUS Version 1.11b", strlen("DARIUS VERSION 1.11b")))
{
MDFN_printf("SuperGfx: Darius Plus\n");
IsSGX = 1;
}
if(crc == 0x4c2126b0)
{
MDFN_printf("SuperGfx: Aldynes\n");
IsSGX = 1;
}
if(crc == 0x8c4588e2)
{
MDFN_printf("SuperGfx: 1941 - Counter Attack\n");
IsSGX = 1;
}
if(crc == 0x1f041166)
{
MDFN_printf("SuperGfx: Madouou Granzort\n");
IsSGX = 1;
}
if(crc == 0xb486a8ed)
{
MDFN_printf("SuperGfx: Daimakaimura\n");
IsSGX = 1;
}
if(crc == 0x3b13af61)
{
MDFN_printf("SuperGfx: Battle Ace\n");
IsSGX = 1;
}
return(LoadCommon());
}
static void LoadCommonPre(void)
{
// FIXME: Make these globals less global!
pce_overclocked = MDFN_GetSettingUI("pce_fast.ocmultiplier");
PCE_ACEnabled = MDFN_GetSettingB("pce_fast.arcadecard");
if(pce_overclocked > 1)
MDFN_printf(_("CPU overclock: %dx\n"), pce_overclocked);
if(MDFN_GetSettingUI("pce_fast.cdspeed") > 1)
MDFN_printf(_("CD-ROM speed: %ux\n"), (unsigned int)MDFN_GetSettingUI("pce_fast.cdspeed"));
memset(HuCPUFastMap, 0, sizeof(HuCPUFastMap));
for(int x = 0; x < 0x100; x++)
{
PCERead[x] = PCEBusRead;
PCEWrite[x] = PCENullWrite;
}
MDFNMP_Init(1024, (1 << 21) / 1024);
}
static int LoadCommon(void)
{
IsSGX |= MDFN_GetSettingB("pce_fast.forcesgx") ? 1 : 0;
// Don't modify IsSGX past this point.
VDC_Init(IsSGX);
if(IsSGX)
{
MDFN_printf("SuperGrafx Emulation Enabled.\n");
PCERead[0xF8] = PCERead[0xF9] = PCERead[0xFA] = PCERead[0xFB] = BaseRAMReadSGX;
PCEWrite[0xF8] = PCEWrite[0xF9] = PCEWrite[0xFA] = PCEWrite[0xFB] = BaseRAMWriteSGX;
for(int x = 0xf8; x < 0xfb; x++)
HuCPUFastMap[x] = BaseRAM - 0xf8 * 8192;
PCERead[0xFF] = IOReadSGX;
}
else
{
PCERead[0xF8] = BaseRAMRead;
PCERead[0xF9] = PCERead[0xFA] = PCERead[0xFB] = BaseRAMRead_Mirrored;
PCEWrite[0xF8] = BaseRAMWrite;
PCEWrite[0xF9] = PCEWrite[0xFA] = PCEWrite[0xFB] = BaseRAMWrite_Mirrored;
for(int x = 0xf8; x < 0xfb; x++)
HuCPUFastMap[x] = BaseRAM - x * 8192;
PCERead[0xFF] = IORead;
}
MDFNMP_AddRAM(IsSGX ? 32768 : 8192, 0xf8 * 8192, BaseRAM);
PCEWrite[0xFF] = IOWrite;
HuC6280_Init();
psg = new PCE_PSG(&sbuf[0], &sbuf[1], PCE_PSG::REVISION_ENHANCED); //HUC6280A);
psg->SetVolume(1.0);
if(PCE_IsCD)
{
unsigned int cdpsgvolume = MDFN_GetSettingUI("pce_fast.cdpsgvolume");
if(cdpsgvolume != 100)
{
MDFN_printf(_("CD PSG Volume: %d%%\n"), cdpsgvolume);
}
psg->SetVolume(0.678 * cdpsgvolume / 100);
}
PCEINPUT_Init();
PCE_Power();
MDFNGameInfo->LayerNames = IsSGX ? "BG0\0SPR0\0BG1\0SPR1\0" : "Background\0Sprites\0";
MDFNGameInfo->fps = (uint32)((double)7159090.90909090 / 455 / 263 * 65536 * 256);
// Clean this up:
if(!MDFN_GetSettingB("pce_fast.correct_aspect"))
MDFNGameInfo->fb_width = 682;
{
MDFNGameInfo->nominal_width = MDFN_GetSettingB("pce_fast.correct_aspect") ? 320 : 341;
MDFNGameInfo->nominal_height = MDFN_GetSettingUI("pce_fast.slend") - MDFN_GetSettingUI("pce_fast.slstart") + 1;
MDFNGameInfo->lcm_width = MDFN_GetSettingB("pce_fast.correct_aspect") ? 1024 : 341;
MDFNGameInfo->lcm_height = MDFNGameInfo->nominal_height;
}
return(1);
}
static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
{
static const uint8 magic_test[0x20] = { 0x82, 0xB1, 0x82, 0xCC, 0x83, 0x76, 0x83, 0x8D, 0x83, 0x4F, 0x83, 0x89, 0x83, 0x80, 0x82, 0xCC,
0x92, 0x98, 0x8D, 0xEC, 0x8C, 0xA0, 0x82, 0xCD, 0x8A, 0x94, 0x8E, 0xAE, 0x89, 0xEF, 0x8E, 0xD0
};
uint8 sector_buffer[2048];
CDIF *cdiface = (*CDInterfaces)[0];
CDUtility::TOC toc;
bool ret = FALSE;
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(!memcmp((char*)sector_buffer, (char *)magic_test, 0x20))
ret = TRUE;
// PCE CD BIOS apparently only looks at the first data track.
break;
}
}
// If it's a PC-FX CD(Battle Heat), return false.
// This is very kludgy.
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(false);
}
}
}
// Now, test for the Games Express CD games. The GE BIOS seems to always look at sector 0x10, but only if the first track is a
// data track.
if(toc.first_track == 1 && (toc.tracks[1].control & 0x4))
{
if(cdiface->ReadSector(sector_buffer, 0x10, 1))
{
if(!memcmp((char *)sector_buffer + 0x8, "HACKER CD ROM SYSTEM", 0x14))
{
ret = TRUE;
}
}
}
return(ret);
}
static int LoadCD(std::vector<CDIF *> *CDInterfaces)
{
std::string bios_path = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0, MDFN_GetSettingS("pce_fast.cdbios").c_str() );
IsSGX = 0;
LoadCommonPre();
if(!HuCLoadCD(bios_path.c_str()))
return(0);
SCSICD_SetDisc(true, NULL, true);
SCSICD_SetDisc(false, (*CDInterfaces)[0], true);
return(LoadCommon());
}
static void CloseGame(void)
{
HuCClose();
VDC_Close();
if(psg)
{
delete psg;
psg = NULL;
}
}
static void Emulate(EmulateSpecStruct *espec)
{
INPUT_Frame();
MDFNMP_ApplyPeriodicCheats();
if(espec->VideoFormatChanged)
VDC_SetPixelFormat(espec->surface->format); //.Rshift, espec->surface->format.Gshift, espec->surface->format.Bshift);
if(espec->SoundFormatChanged)
{
for(int y = 0; y < 2; y++)
{
sbuf[y].set_sample_rate(espec->SoundRate ? espec->SoundRate : 44100, 50);
sbuf[y].clock_rate((long)(PCE_MASTER_CLOCK / 3));
sbuf[y].bass_freq(20);
}
}
VDC_RunFrame(espec->surface, &espec->DisplayRect, espec->LineWidths, /* IsHES ? 1 : */espec->skip);
if(PCE_IsCD)
{
int32 dummy_ne;
dummy_ne = PCECD_Run(HuCPU.timestamp * 3);
}
psg->EndFrame(HuCPU.timestamp / pce_overclocked);
if(espec->SoundBuf)
{
for(int y = 0; y < 2; y++)
{
sbuf[y].end_frame(HuCPU.timestamp / pce_overclocked);
espec->SoundBufSize = sbuf[y].read_samples(espec->SoundBuf + y, espec->SoundBufMaxSize, 1);
}
}
espec->MasterCycles = HuCPU.timestamp * 3;
INPUT_FixTS(HuCPU.timestamp);
HuC6280_ResetTS();
if(PCE_IsCD)
PCECD_ResetTS();
}
static int StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFARRAY(BaseRAM, IsSGX? 32768 : 8192),
SFVAR(PCEIODataBuffer),
SFEND
};
//for(int i = 8192; i < 32768; i++)
// if(BaseRAM[i] != 0xFF)
// printf("%d %02x\n", i, BaseRAM[i]);
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MAIN");
ret &= HuC6280_StateAction(sm, load, data_only);
ret &= VDC_StateAction(sm, load, data_only);
ret &= psg->StateAction(sm, load, data_only);
ret &= INPUT_StateAction(sm, load, data_only);
ret &= HuC_StateAction(sm, load, data_only);
if(load)
{
}
return(ret);
}
void PCE_Power(void)
{
memset(BaseRAM, 0x00, sizeof(BaseRAM));
if(!IsSGX)
for(int i = 8192; i < 32768; i++)
BaseRAM[i] = 0xFF;
PCEIODataBuffer = 0xFF;
HuC6280_Power();
VDC_Power();
psg->Power(HuCPU.timestamp / pce_overclocked);
HuC_Power();
if(PCE_IsCD)
{
int32 dummy_ne;
dummy_ne = PCECD_Power(HuCPU.timestamp * 3);
}
}
static void DoSimpleCommand(int cmd)
{
switch(cmd)
{
case MDFN_MSC_RESET: PCE_Power(); break;
case MDFN_MSC_POWER: PCE_Power(); break;
}
}
static MDFNSetting PCESettings[] =
{
/*
{ "pce_fast.input.port1", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Input device for input port 1."), NULL, MDFNST_STRING, "gamepad", NULL, NULL },
{ "pce_fast.input.port2", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Input device for input port 2."), NULL, MDFNST_STRING, "gamepad", NULL, NULL },
{ "pce_fast.input.port3", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Input device for input port 3."), NULL, MDFNST_STRING, "gamepad", NULL, NULL },
{ "pce_fast.input.port4", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Input device for input port 4."), NULL, MDFNST_STRING, "gamepad", NULL, NULL },
{ "pce_fast.input.port5", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Input device for input port 5."), NULL, MDFNST_STRING, "gamepad", NULL, NULL },
*/
{ "pce_fast.input.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable multitap(TurboTap) emulation."), NULL, MDFNST_BOOL, "1" },
{ "pce_fast.correct_aspect", MDFNSF_CAT_VIDEO, gettext_noop("Correct the aspect ratio."), NULL, MDFNST_BOOL, "1" },
{ "pce_fast.slstart", MDFNSF_NOFLAGS, gettext_noop("First rendered scanline."), NULL, MDFNST_UINT, "4", "0", "239" },
{ "pce_fast.slend", MDFNSF_NOFLAGS, gettext_noop("Last rendered scanline."), NULL, MDFNST_UINT, "235", "0", "239" },
{ "pce_fast.mouse_sensitivity", MDFNSF_NOFLAGS, gettext_noop("Mouse sensitivity."), NULL, MDFNST_FLOAT, "0.50", NULL, NULL, NULL, PCEINPUT_SettingChanged },
{ "pce_fast.disable_softreset", MDFNSF_NOFLAGS, gettext_noop("If set, when RUN+SEL are pressed simultaneously, disable both buttons temporarily."), NULL, MDFNST_BOOL, "0", NULL, NULL, NULL, PCEINPUT_SettingChanged },
{ "pce_fast.forcesgx", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Force SuperGrafx emulation."), NULL, MDFNST_BOOL, "0" },
{ "pce_fast.arcadecard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable Arcade Card emulation."), NULL, MDFNST_BOOL, "1" },
{ "pce_fast.ocmultiplier", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("CPU overclock multiplier."), NULL, MDFNST_UINT, "1", "1", "100"},
{ "pce_fast.cdspeed", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("CD-ROM data transfer speed multiplier."), NULL, MDFNST_UINT, "1", "1", "100" },
{ "pce_fast.nospritelimit", MDFNSF_NOFLAGS, gettext_noop("Remove 16-sprites-per-scanline hardware limit."), NULL, MDFNST_BOOL, "0" },
{ "pce_fast.cdbios", MDFNSF_EMU_STATE, gettext_noop("Path to the CD BIOS"), NULL, MDFNST_STRING, "syscard3.pce" },
{ "pce_fast.adpcmlp", MDFNSF_NOFLAGS, gettext_noop("Enable lowpass filter dependent on playback-frequency."), NULL, MDFNST_BOOL, "0" },
{ "pce_fast.cdpsgvolume", MDFNSF_NOFLAGS, gettext_noop("PSG volume when playing a CD game."), NULL, MDFNST_UINT, "100", "0", "200" },
{ "pce_fast.cddavolume", MDFNSF_NOFLAGS, gettext_noop("CD-DA volume."), NULL, MDFNST_UINT, "100", "0", "200" },
{ "pce_fast.adpcmvolume", MDFNSF_NOFLAGS, gettext_noop("ADPCM volume."), NULL, MDFNST_UINT, "100", "0", "200" },
{ NULL }
};
static uint8 MemRead(uint32 addr)
{
return(PCERead[(addr / 8192) & 0xFF](addr));
}
static const FileExtensionSpecStruct KnownExtensions[] =
{
{ ".pce", gettext_noop("PC Engine ROM Image") },
{ ".hes", gettext_noop("PC Engine Music Rip") },
{ ".sgx", gettext_noop("SuperGrafx ROM Image") },
{ NULL, NULL }
};
MDFNGI EmulatedPCE_Fast =
{
"pce_fast",
"PC Engine (CD)/TurboGrafx 16 (CD)/SuperGrafx",
KnownExtensions,
MODPRIO_INTERNAL_LOW,
NULL,
&PCEInputInfo,
Load,
TestMagic,
LoadCD,
TestMagicCD,
CloseGame,
VDC_SetLayerEnableMask,
NULL,
NULL,
NULL,
NULL,
NULL,
MemRead,
false,
StateAction,
Emulate,
PCEINPUT_SetInput,
DoSimpleCommand,
PCESettings,
MDFN_MASTERCLOCK_FIXED(PCE_MASTER_CLOCK),
0,
true, // Multires possible?
0, // lcm_width
0, // lcm_height
NULL, // Dummy
320, // Nominal width
232, // Nominal height
512, // Framebuffer width
242, // Framebuffer height
2, // Number of output sound channels
};

View File

@ -0,0 +1,35 @@
#ifndef _PCE_H
#include "../mednafen-types.h"
#include "../mednafen.h"
#include "../state.h"
#include "../general.h"
#include "../memory.h"
#define PCE_MASTER_CLOCK 21477272.727273
#define DECLFR(x) uint8 MDFN_FASTCALL x (uint32 A)
#define DECLFW(x) void MDFN_FASTCALL x (uint32 A, uint8 V)
extern uint8 ROMSpace[0x88 * 8192 + 8192];
typedef void (MDFN_FASTCALL *writefunc)(uint32 A, uint8 V);
typedef uint8 (MDFN_FASTCALL *readfunc)(uint32 A);
extern uint8 PCEIODataBuffer;
bool PCE_InitCD(void);
#include "pce_huc6280.h"
extern bool PCE_ACEnabled; // Arcade Card emulation enabled?
void PCE_Power(void);
extern readfunc PCERead[0x100];
extern writefunc PCEWrite[0x100];
extern int pce_overclocked;
extern uint8 BaseRAM[32768 + 8192];
#define _PCE_H
#endif

View File

@ -0,0 +1,744 @@
/* 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 "pce.h"
#include "vdc.h"
#include "pce_huc6280.h"
HuC6280 HuCPU;
uint8 *HuCPUFastMap[0x100];
#define HU_PC PC_local //HuCPU.PC
#define HU_PC_base HuCPU.PC_base
#define HU_A HuCPU.A
#define HU_X X_local //HuCPU.X
#define HU_Y Y_local //HuCPU.Y
#define HU_S HuCPU.S
#define HU_P P_local //HuCPU.P
#define HU_PI HuCPU.mooPI
#define HU_IRQlow HuCPU.IRQlow
#define HU_Page1 Page1_local
//HuCPU.Page1
//Page1_local //HuCPU.Page1
#ifdef HUC6280_LAZY_FLAGS
#define HU_ZNFlags HuCPU.ZNFlags
#endif
#ifdef HUC6280_CRAZY_VERSION
#define LOAD_LOCALS_PC() register uint8 *PC_local = HuCPU.PC;
#else
#define LOAD_LOCALS_PC() register uint32 PC_local /*asm ("edi")*/ = HuCPU.PC; // asm ("edi") = HuCPU.PC;
#endif
#define LOAD_LOCALS() \
LOAD_LOCALS_PC(); \
uint8 X_local = HuCPU.X; \
uint8 Y_local = HuCPU.Y; \
uint8 P_local = HuCPU.P; \
uint8 *Page1_local = HuCPU.Page1;
#define SAVE_LOCALS() HuCPU.PC = PC_local; \
HuCPU.X = X_local; \
HuCPU.Y = Y_local; \
HuCPU.P = P_local; \
HuCPU.Page1 = Page1_local;
#ifdef HUC6280_LAZY_FLAGS
#define COMPRESS_FLAGS() HU_P &= ~(N_FLAG | Z_FLAG); HU_P |= ((HU_ZNFlags >> 24) & 0x80) | ((HU_ZNFlags & 0xFF) ? 0 : Z_FLAG);
//((((HU_ZNFlags & 0xFF) - 1) >> 8) & Z_FLAG);
#define EXPAND_FLAGS() HU_ZNFlags = (HU_P << 24) | ((HU_P & Z_FLAG) ^ Z_FLAG);
#else
#define COMPRESS_FLAGS()
#define EXPAND_FLAGS()
#endif
#ifdef HUC6280_CRAZY_VERSION
#define GetRealPC() ((unsigned int)(HU_PC - HU_PC_base))
#define GetRealPC_EXTERNAL() ((unsigned int)(HuCPU.PC - HuCPU.PC_base))
#else
#define GetRealPC() (HU_PC)
#define GetRealPC_EXTERNAL() (HuCPU.PC)
#endif
#ifdef HUC6280_CRAZY_VERSION
#define SetPC(value) { unsigned int tempmoo = value; HU_PC = &HuCPU.FastPageR[tempmoo >> 13][tempmoo]; \
HU_PC_base = HU_PC - tempmoo; }
#define SetPC_EXTERNAL(value) { unsigned int tempmoo = value; \
HuCPU.PC = &HuCPU.FastPageR[tempmoo >> 13][tempmoo]; HuCPU.PC_base = HuCPU.PC - tempmoo; }
#else
#define SetPC(value) { HU_PC = (value); }
#define SetPC_EXTERNAL(value) { HuCPU.PC = (value); }
#endif
// Page change PC, GET IT?!
#ifdef HUC6280_CRAZY_VERSION
#define FixPC_PC() SetPC(GetRealPC());
#else
#define FixPC_PC()
#endif
#define IncPC() HU_PC++;
#ifdef HUC6280_CRAZY_VERSION
#define RdAtPC() (*HU_PC)
//#define RdAtAndIncPC_16() (HU_PC += 2, *(uint16 *)(HU_PC - 2))
#else
#define RdAtPC() RdOp(HU_PC)
//#define RdAtAndIncPC_16() (RdOp(HU_PC++) | ((RdOp(HU_PC++) << 8)))
#endif
// If we change this definition, we'll need to also fix HuC6280_StealCycle() in huc6280.h
#define ADDCYC(x) { HuCPU.timestamp += x; }
static uint8 dummy_bank[8192 + 8192]; // + 8192 for PC-as-ptr safety padding
#define SET_MPR(arg_i, arg_v) \
{ \
const unsigned int wmpr = arg_i, wbank = arg_v; \
if(wmpr == 1) \
{ \
if(wbank != 0xF8 || !HuCPUFastMap[wbank]) \
printf("Crazy page 1: %02x\n", wbank); \
HU_Page1 = HuCPUFastMap[wbank] ? HuCPUFastMap[wbank] + wbank * 8192 : dummy_bank; \
} \
HuCPU.MPR[wmpr] = wbank; \
HuCPU.FastPageR[wmpr] = HuCPUFastMap[wbank] ? (HuCPUFastMap[wbank] + wbank * 8192) - wmpr * 8192 : (dummy_bank - wmpr * 8192); \
}
void HuC6280_SetMPR(int i, int v)
{
uint8 *Page1_local = HuCPU.Page1;
SET_MPR(i, v);
HuCPU.Page1 = Page1_local;
}
static void HuC6280_FlushMPRCache(void)
{
for(int x = 0; x < 9; x++)
HuC6280_SetMPR(x, HuCPU.MPR[x & 0x7]);
}
static INLINE uint8 RdMem(unsigned int A)
{
uint8 wmpr = HuCPU.MPR[A >> 13];
return(PCERead[wmpr]((wmpr << 13) | (A & 0x1FFF)));
}
static INLINE uint16 RdMem16(unsigned int A)
{
return(RdMem(A) | (RdMem(A + 1) << 8));
}
static INLINE void WrMem(unsigned int A, uint8 V)
{
uint8 wmpr = HuCPU.MPR[A >> 13];
PCEWrite[wmpr]((wmpr << 13) | (A & 0x1FFF), V);
}
static INLINE uint8 RdOp(unsigned int A)
{
return(HuCPU.FastPageR[A >> 13][A]);
}
#define PUSH(V) \
{ \
HU_Page1[0x100 + HU_S] = V; \
HU_S--; \
}
#define PUSH_PC() \
{ \
unsigned int real_pc = GetRealPC(); \
PUSH(real_pc >> 8); \
PUSH(real_pc); \
}
#define POP() HU_Page1[0x100 + ++HU_S]
#define POP_PC() \
{ \
unsigned int npc; \
npc = POP(); \
npc |= POP() << 8; \
SetPC(npc); \
}
// Hopefully we never RTS to 0x0000. ;)
#define POP_PC_AP() \
{ \
uint32 npc; \
npc = POP(); \
npc |= POP() << 8; \
npc++; \
SetPC(npc); \
}
/* Some of these operations will only make sense if you know what the flag
constants are. */
#ifdef HUC6280_LAZY_FLAGS
#define X_ZN(zort) { HU_ZNFlags = (int32)(int8)(uint8)(zort); }
#define X_ZN_BIT(opres, argie) { HU_ZNFlags = (opres) | ((argie) << 24); }
#else
static uint8 ZNTable[256];
#define X_ZN(zort) HU_P&=~(Z_FLAG|N_FLAG);HU_P|=ZNTable[zort]
#define X_ZN_BIT(opres, argie) { HU_P &= ~(Z_FLAG | N_FLAG); HU_P |= ZNTable[opres] & Z_FLAG; HU_P |= argie & N_FLAG; }
#endif
#define JR(cond) \
{ \
if(cond) \
{ \
int32 disp; \
disp = 1 + (int8)RdAtPC(); \
ADDCYC(2); \
HU_PC+=disp; \
} \
else IncPC(); \
}
#define BRA \
{ \
int32 disp; \
disp = 1 + (int8)RdAtPC(); \
HU_PC+=disp; \
}
#define BBRi(bitto) JR(!(x & (1 << bitto)))
#define BBSi(bitto) JR(x & (1 << bitto))
#define ST0 VDC_Write_ST(0, x)
#define ST1 VDC_Write_ST(2, x)
#define ST2 VDC_Write_ST(3, x)
#define LDA HU_A=x;X_ZN(HU_A)
#define LDX HU_X=x;X_ZN(HU_X)
#define LDY HU_Y=x;X_ZN(HU_Y)
/* All of the freaky arithmetic operations. */
#define AND HU_A&=x;X_ZN(HU_A);
// FIXME:
#define BIT HU_P&=~V_FLAG; X_ZN_BIT(x & HU_A, x); HU_P |= x & V_FLAG;
#define EOR HU_A^=x;X_ZN(HU_A);
#define ORA HU_A|=x;X_ZN(HU_A);
#define ADC { \
if(HU_P & D_FLAG) \
{ \
uint32 low = (HU_A & 0x0F) + (x & 0x0F) + (HU_P & 1); \
uint32 high = (HU_A & 0xF0) + (x & 0xF0); \
HU_P &= ~C_FLAG; \
if(low > 0x09) { high += 0x10; low += 0x06; } \
if(high > 0x90) { high += 0x60; } \
HU_P |= (high >> 8) & C_FLAG; \
HU_A = (low & 0x0F) | (high & 0xF0); \
X_ZN(HU_A); \
} \
else \
{ \
uint32 l=HU_A+x+(HU_P&1); \
HU_P&=~(C_FLAG|V_FLAG); \
HU_P|=((((HU_A^x)&0x80)^0x80) & ((HU_A^l)&0x80))>>1; \
HU_P|=(l>>8)&C_FLAG; \
HU_A=l; \
X_ZN(HU_A); \
} \
}
#define SBC if(HU_P & D_FLAG) \
{ \
uint32 c = (HU_P & 1) ^ 1; \
uint32 l = HU_A - x - c; \
uint32 low = (HU_A & 0x0f) - (x & 0x0f) - c; \
uint32 high = (HU_A & 0xf0) - (x & 0xf0); \
HU_P &= ~(C_FLAG); \
if(low & 0xf0) low -= 0x06; \
if(low & 0x80) high -= 0x10; \
if(high & 0x0f00) high -= 0x60; \
HU_P |= ((l >> 8) & C_FLAG) ^ C_FLAG; \
HU_A = (low & 0x0F) | (high & 0xf0); \
X_ZN(HU_A); \
} else { \
uint32 l=HU_A-x-((HU_P&1)^1); \
HU_P&=~(C_FLAG|V_FLAG); \
HU_P|=((HU_A^l)&(HU_A^x)&0x80)>>1; \
HU_P|=((l>>8)&C_FLAG)^C_FLAG; \
HU_A=l; \
X_ZN(HU_A); \
}
#define CMPL(a1,a2) { \
uint32 t=a1-a2; \
X_ZN(t&0xFF); \
HU_P&=~C_FLAG; \
HU_P|=((t>>8)&C_FLAG)^C_FLAG; \
}
#define TAM for(int i = 0; i < 8; i ++) { \
if(x & (1 << i)) \
{ \
SET_MPR(i, HU_A); \
} \
} SET_MPR(8, HuCPU.MPR[0]);
#define TMA for(int i = 0; i < 8; i ++) { \
if(x & (1 << i)) \
HU_A = HuCPU.MPR[i]; \
}
#define CSL
#define CSH
#define RMB(bitto) x &= ~(1 << (bitto & 7))
#define SMB(bitto) x |= 1 << (bitto & 7)
// FIXME
#define TSB { HU_P &= ~V_FLAG; X_ZN_BIT(x | HU_A, x); HU_P |= x & V_FLAG; x |= HU_A; }
#define TRB { HU_P &= ~V_FLAG; X_ZN_BIT(x & ~HU_A, x); HU_P |= x & V_FLAG; x &= ~HU_A; }
#define TST { HU_P &= ~V_FLAG; X_ZN_BIT(x & zoomhack, x); HU_P |= x & V_FLAG; }
#define CMP CMPL(HU_A,x)
#define CPX CMPL(HU_X,x)
#define CPY CMPL(HU_Y,x)
/* The following operations modify the byte being worked on. */
#define DEC x--;X_ZN(x)
#define INC x++;X_ZN(x)
#define ASL HU_P&=~C_FLAG;HU_P|=x>>7;x<<=1;X_ZN(x)
#define LSR HU_P&=~C_FLAG;HU_P|=x&1;x>>=1;X_ZN(x)
#define ROL { \
uint8 l=x>>7; \
x<<=1; \
x|=HU_P&C_FLAG; \
HU_P&=~C_FLAG; \
HU_P|=l; \
X_ZN(x); \
}
#define ROR { \
uint8 l=x&1; \
x>>=1; \
x|=(HU_P&C_FLAG)<<7; \
HU_P&=~C_FLAG; \
HU_P|=l; \
X_ZN(x); \
}
/* Absolute */
#define GetAB(target) \
{ \
target=RdAtPC(); \
IncPC(); \
target|=RdAtPC()<<8; \
IncPC(); \
}
/* Absolute Indexed(for reads) */
#define GetABI(target, i) \
{ \
unsigned int tmp; \
GetAB(tmp); \
target=tmp; \
target+=i; \
}
/* Zero Page */
#define GetZP(target) \
{ \
target=RdAtPC(); \
IncPC(); \
}
/* Zero Page Indexed */
#define GetZPI(target,i) \
{ \
target=i+RdAtPC(); \
IncPC(); \
}
/* Indirect */
#define GetIND(target) \
{ \
uint8 tmp; \
tmp=RdAtPC(); \
IncPC(); \
target=HU_Page1[tmp]; \
tmp++; \
target|=HU_Page1[tmp]<<8; \
}
/* Indexed Indirect */
#define GetIX(target) \
{ \
uint8 tmp; \
tmp=RdAtPC(); \
IncPC(); \
tmp+=HU_X; \
target=HU_Page1[tmp]; \
tmp++; \
target|=HU_Page1[tmp] <<8; \
}
/* Indirect Indexed(for reads) */
#define GetIY(target) \
{ \
unsigned int rt; \
uint8 tmp; \
tmp=RdAtPC(); \
rt=HU_Page1[tmp]; \
tmp++; \
rt|=HU_Page1[tmp]<<8; \
target = (rt + HU_Y); \
IncPC(); \
}
/* Now come the macros to wrap up all of the above stuff addressing mode functions
and operation macros. Note that operation macros will always operate(redundant
redundant) on the variable "x".
*/
#define RMW_A(op) {uint8 x=HU_A; op; HU_A=x; break; } /* Meh... */
#define RMW_AB(op) {unsigned int EA; uint8 x; GetAB(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
#define RMW_ABI(reg,op) {unsigned int EA; uint8 x; GetABI(EA,reg); x=RdMem(EA); op; WrMem(EA,x); break; }
#define RMW_ABX(op) RMW_ABI(HU_X,op)
#define RMW_ABY(op) RMW_ABI(HU_Y,op)
#define RMW_IND(op) { unsigned int EA; uint8 x; GetIND(EA); x = RdMem(EA); op; WrMem(EA, x); break; }
#define RMW_IX(op) { unsigned int EA; uint8 x; GetIX(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
#define RMW_IY(op) { unsigned int EA; uint8 x; GetIY(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
#define RMW_ZP(op) { uint8 EA; uint8 x; GetZP(EA); x=HU_Page1[EA]; op; HU_Page1[EA] = x; break; }
#define RMW_ZPX(op) { uint8 EA; uint8 x; GetZPI(EA,HU_X); x=HU_Page1[EA]; op; HU_Page1[EA] = x; break;}
#define LD_IM(op) { uint8 x; x=RdAtPC(); IncPC(); op; break; }
#define LD_ZP(op) { uint8 EA; uint8 x; GetZP(EA); x=HU_Page1[EA]; op; break; }
#define LD_ZPX(op) { uint8 EA; uint8 x; GetZPI(EA,HU_X); x=HU_Page1[EA]; op; break; }
#define LD_ZPY(op) { uint8 EA; uint8 x; GetZPI(EA,HU_Y); x=HU_Page1[EA]; op; break; }
#define LD_AB(op) { unsigned int EA; uint8 x; GetAB(EA); x=RdMem(EA); op; break; }
#define LD_ABI(reg,op) { unsigned int EA; uint8 x; GetABI(EA,reg); x=RdMem(EA); op; break; }
#define LD_ABX(op) LD_ABI(HU_X,op)
#define LD_ABY(op) LD_ABI(HU_Y,op)
#define LD_IND(op) { unsigned int EA; uint8 x; GetIND(EA); x=RdMem(EA); op; break; }
#define LD_IX(op) { unsigned int EA; uint8 x; GetIX(EA); x=RdMem(EA); op; break; }
#define LD_IY(op) { unsigned int EA; uint8 x; GetIY(EA); x=RdMem(EA); op; break; }
#define BMT_PREHONK(pork) HuCPU.in_block_move = IBM_##pork;
#define BMT_HONKHONK(pork) if(HuCPU.timestamp >= next_user_event) goto GetOutBMT; continue_the_##pork:
#define BMT_TDD BMT_PREHONK(TDD); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src--; HuCPU.bmt_dest--; BMT_HONKHONK(TDD); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
#define BMT_TAI BMT_PREHONK(TAI); {HuCPU.bmt_alternate = 0; do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src + HuCPU.bmt_alternate)); HuCPU.bmt_dest++; HuCPU.bmt_alternate ^= 1; BMT_HONKHONK(TAI); HuCPU.bmt_length--; } while(HuCPU.bmt_length); }
#define BMT_TIA BMT_PREHONK(TIA); {HuCPU.bmt_alternate = 0; do { ADDCYC(6); WrMem(HuCPU.bmt_dest + HuCPU.bmt_alternate, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; HuCPU.bmt_alternate ^= 1; BMT_HONKHONK(TIA); HuCPU.bmt_length--; } while(HuCPU.bmt_length); }
#define BMT_TII BMT_PREHONK(TII); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; HuCPU.bmt_dest++; BMT_HONKHONK(TII); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
#define BMT_TIN BMT_PREHONK(TIN); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; BMT_HONKHONK(TIN); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
// Block memory transfer load
#define LD_BMT(op) { PUSH(HU_Y); PUSH(HU_A); PUSH(HU_X); GetAB(HuCPU.bmt_src); GetAB(HuCPU.bmt_dest); GetAB(HuCPU.bmt_length); op; HuCPU.in_block_move = 0; HU_X = POP(); HU_A = POP(); HU_Y = POP(); break; }
#define ST_ZP(r) {uint8 EA; GetZP(EA); HU_Page1[EA] = r; break;}
#define ST_ZPX(r) {uint8 EA; GetZPI(EA,HU_X); HU_Page1[EA] = r; break;}
#define ST_ZPY(r) {uint8 EA; GetZPI(EA,HU_Y); HU_Page1[EA] = r; break;}
#define ST_AB(r) {unsigned int EA; GetAB(EA); WrMem(EA, r); break;}
#define ST_ABI(reg,r) {unsigned int EA; GetABI(EA,reg); WrMem(EA,r); break; }
#define ST_ABX(r) ST_ABI(HU_X,r)
#define ST_ABY(r) ST_ABI(HU_Y,r)
#define ST_IND(r) {unsigned int EA; GetIND(EA); WrMem(EA,r); break; }
#define ST_IX(r) {unsigned int EA; GetIX(EA); WrMem(EA,r); break; }
#define ST_IY(r) {unsigned int EA; GetIY(EA); WrMem(EA,r); break; }
static const uint8 CycTable[256] =
{
/*0x00*/ 8, 7, 3, 4, 6, 4, 6, 7, 3, 2, 2, 2, 7, 5, 7, 6,
/*0x10*/ 2, 7, 7, 4, 6, 4, 6, 7, 2, 5, 2, 2, 7, 5, 7, 6,
/*0x20*/ 7, 7, 3, 4, 4, 4, 6, 7, 4, 2, 2, 2, 5, 5, 7, 6,
/*0x30*/ 2, 7, 7, 2, 4, 4, 6, 7, 2, 5, 2, 2, 5, 5, 7, 6,
/*0x40*/ 7, 7, 3, 4, 8, 4, 6, 7, 3, 2, 2, 2, 4, 5, 7, 6,
/*0x50*/ 2, 7, 7, 5, 3, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,
/*0x60*/ 7, 7, 2, 2, 4, 4, 6, 7, 4, 2, 2, 2, 7, 5, 7, 6,
/*0x70*/ 2, 7, 7, 17, 4, 4, 6, 7, 2, 5, 4, 2, 7, 5, 7, 6,
/*0x80*/ 4, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,
/*0x90*/ 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,
/*0xA0*/ 2, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,
/*0xB0*/ 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,
/*0xC0*/ 2, 7, 2, 17, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,
/*0xD0*/ 2, 7, 7, 17, 3, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,
/*0xE0*/ 2, 7, 2, 17, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,
/*0xF0*/ 2, 7, 7, 17, 2, 4, 6, 7, 2, 5, 4, 2, 2, 5, 7, 6,
};
void HuC6280_IRQBegin(int w)
{
HU_IRQlow|=w;
}
void HuC6280_IRQEnd(int w)
{
HU_IRQlow&=~w;
}
void HuC6280_Reset(void)
{
HuCPU.timer_next_timestamp = HuCPU.timestamp + 1024;
HuCPU.timer_load = 0;
HuCPU.timer_value = 0;
HuCPU.timer_status = 0;
HuCPU.in_block_move = 0;
unsigned int npc;
HuCPU.IRQMask = HuCPU.IRQMaskDelay = 7;
HuC6280_SetMPR(0, 0xFF);
HuC6280_SetMPR(1, 0xF8);
for(int i = 2; i < 8; i++)
HuC6280_SetMPR(i, 0);
npc = RdMem16(0xFFFE);
#define PC_local HuCPU.PC
SetPC(npc);
#undef PC_local
HuCPU.mooPI = I_FLAG;
HuCPU.P = I_FLAG;
HU_IRQlow = 0;
}
void HuC6280_Init(void)
{
memset((void *)&HuCPU,0,sizeof(HuCPU));
memset(dummy_bank, 0, sizeof(dummy_bank));
#ifdef HUC6280_LAZY_FLAGS
#else
for(int x=0; x < 256; x++)
if(!x) ZNTable[x]=Z_FLAG;
else if (x&0x80) ZNTable[x]=N_FLAG;
else ZNTable[x]=0;
#endif
}
void HuC6280_Power(void)
{
HuCPU.IRQlow = 0;
HuCPU.A = 0;
HuCPU.X = 0;
HuCPU.Y = 0;
HuCPU.S = 0;
HuCPU.P = 0;
HuCPU.mooPI = 0;
HuCPU.PC = 0;
HuCPU.timestamp = 0;
for(int i = 0; i < 9; i++)
{
HuCPU.MPR[i] = 0;
HuCPU.FastPageR[i] = NULL;
}
HuC6280_Reset();
}
void HuC6280_Run(int32 cycles)
{
const int32 next_user_event = HuCPU.previous_next_user_event + cycles * pce_overclocked;
HuCPU.previous_next_user_event = next_user_event;
LOAD_LOCALS();
if(HuCPU.timestamp >= next_user_event)
return;
int32 next_event;
if(HuCPU.in_block_move)
{
next_event = (next_user_event < HuCPU.timer_next_timestamp) ? next_user_event : HuCPU.timer_next_timestamp;
switch(HuCPU.in_block_move)
{
case IBM_TIA: goto continue_the_TIA;
case IBM_TAI: goto continue_the_TAI;
case IBM_TDD: goto continue_the_TDD;
case IBM_TII: goto continue_the_TII;
case IBM_TIN: goto continue_the_TIN;
}
}
while(HuCPU.timestamp < next_user_event)
{
next_event = (next_user_event < HuCPU.timer_next_timestamp) ? next_user_event : HuCPU.timer_next_timestamp;
while(HuCPU.timestamp < next_event)
{
uint8 b1;
if(HU_IRQlow)
{
if(!(HU_PI&I_FLAG))
{
uint32 tmpa = 0;
if(HU_IRQlow & MDFN_IQTIMER & HuCPU.IRQMaskDelay)
tmpa = 0xFFFA;
else if((HU_IRQlow & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay) || ((HU_IRQlow >> 8) & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay))
tmpa = 0xFFF8;
else if(HU_IRQlow & MDFN_IQIRQ2 & HuCPU.IRQMaskDelay)
tmpa = 0xFFF6;
if(tmpa)
{
unsigned int npc;
ADDCYC(8);
PUSH_PC();
COMPRESS_FLAGS();
PUSH((HU_P&~B_FLAG));
HU_P |= I_FLAG;
HU_P &= ~(T_FLAG | D_FLAG);
HU_PI = HU_P;
npc = RdMem16(tmpa);
SetPC(npc);
if(tmpa == 0xFFF8)
HU_IRQlow &= ~0x200;
continue;
}
}
} // end if(HU_IRQlow)
//printf("%04x\n", GetRealPC());
HU_PI = HU_P;
HuCPU.IRQMaskDelay = HuCPU.IRQMask;
b1 = RdAtPC();
ADDCYC(CycTable[b1]);
IncPC();
switch(b1)
{
#include "huc6280_ops.inc"
}
#ifndef HUC6280_EXTRA_CRAZY
FixPC_PC();
#endif
} // end while(HuCPU.timestamp < next_event)
while(HuCPU.timestamp >= HuCPU.timer_next_timestamp)
{
HuCPU.timer_next_timestamp += 1024 * pce_overclocked;
if(HuCPU.timer_status)
{
HuCPU.timer_value --;
if(HuCPU.timer_value < 0)
{
HuCPU.timer_value = HuCPU.timer_load;
HuC6280_IRQBegin(MDFN_IQTIMER);
}
}
}
} // end while(HuCPU.timestamp < next_user_event)
GetOutBMT:
SAVE_LOCALS();
}
void HuC6280_ResetTS(void)
{
HuCPU.timer_next_timestamp -= HuCPU.timestamp;
HuCPU.previous_next_user_event -= HuCPU.timestamp;
HuCPU.timestamp = 0;
}
int HuC6280_StateAction(StateMem *sm, int load, int data_only)
{
uint16 tmp_PC = GetRealPC_EXTERNAL();
#define P_local HuCPU.P
COMPRESS_FLAGS();
SFORMAT SFCPU[]=
{
SFVARN(tmp_PC, "PC"),
SFVARN(HuCPU.A, "A"),
SFVARN(HuCPU.P, "P"),
SFVARN(HuCPU.X, "X"),
SFVARN(HuCPU.Y, "Y"),
SFVARN(HuCPU.S, "S"),
SFVARN(HuCPU.mooPI, "PI"),
SFVARN(HuCPU.IRQMask, "IRQMask"),
SFVARN(HuCPU.IRQMaskDelay, "IRQMaskDelay"),
SFARRAYN(HuCPU.MPR, 8, "MPR"),
SFVARN(HuCPU.timer_status, "timer_status"),
SFVARN(HuCPU.timer_value, "timer_value"),
SFVARN(HuCPU.timer_load, "timer_load"),
SFVARN(HuCPU.IRQlow, "IRQlow"),
SFVARN(HuCPU.in_block_move, "IBM"),
SFVARN(HuCPU.bmt_src, "IBM_SRC"),
SFVARN(HuCPU.bmt_dest, "IBM_DEST"),
SFVARN(HuCPU.bmt_length, "IBM_LENGTH"),
SFVARN(HuCPU.bmt_alternate, "IBM_ALTERNATE"),
SFVARN(HuCPU.timestamp, "timestamp"),
SFVARN(HuCPU.timer_next_timestamp, "timer_next_timestamp"),
SFVARN(HuCPU.previous_next_user_event, "previous_next_user_event"),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, SFCPU, "CPU");
if(load)
{
// Update MPR cache
HuC6280_FlushMPRCache();
// This must be after the MPR cache is updated:
SetPC_EXTERNAL(tmp_PC);
}
EXPAND_FLAGS();
#undef P_local
return(ret);
}

View File

@ -0,0 +1,147 @@
#ifndef _HuC6280H
#define HUC6280_CRAZY_VERSION
//#define HUC6280_EXTRA_CRAZY
#define HUC6280_LAZY_FLAGS
typedef struct __HuC6280
{
#ifdef HUC6280_CRAZY_VERSION
uint8 *PC, *PC_base;
#else
uint16 PC;
#endif
uint8 A,X,Y,S,P,mooPI;
#ifdef HUC6280_LAZY_FLAGS
uint32 ZNFlags;
#endif
uint8 MPR[9]; // 8, + 1 for PC overflow from $ffff to $10000
uint8 *FastPageR[9];
uint8 *Page1;
//uint8 *PAGE1_W;
//const uint8 *PAGE1_R;
uint32 IRQlow; /* Simulated IRQ pin held low(or is it high?).
And other junk hooked on for speed reasons.*/
int32 timestamp;
uint8 IRQMask, IRQMaskDelay;
uint8 timer_status;
int32 timer_value, timer_load;
int32 timer_next_timestamp;
uint32 in_block_move;
uint16 bmt_src, bmt_dest, bmt_length;
uint32 bmt_alternate;
#define IBM_TIA 1
#define IBM_TAI 2
#define IBM_TDD 3
#define IBM_TII 4
#define IBM_TIN 5
int32 previous_next_user_event;
} HuC6280;
void HuC6280_Run(int32 cycles);
void HuC6280_ResetTS(void);
extern HuC6280 HuCPU;
extern uint8 *HuCPUFastMap[0x100];
#define N_FLAG 0x80
#define V_FLAG 0x40
#define T_FLAG 0x20
#define B_FLAG 0x10
#define D_FLAG 0x08
#define I_FLAG 0x04
#define Z_FLAG 0x02
#define C_FLAG 0x01
#define NTSC_CPU 1789772.7272727272727272
#define PAL_CPU 1662607.125
#define MDFN_IQIRQ1 0x002
#define MDFN_IQIRQ2 0x001
#define MDFN_IQTIMER 0x004
#define MDFN_IQRESET 0x020
void HuC6280_Init(void);
void HuC6280_Reset(void);
void HuC6280_Power(void);
void HuC6280_IRQBegin(int w);
void HuC6280_IRQEnd(int w);
int HuC6280_StateAction(StateMem *sm, int load, int data_only);
static INLINE void HuC6280_StealCycle(void)
{
HuCPU.timestamp++;
}
static INLINE uint8 HuC6280_TimerRead(unsigned int A)
{
uint8 tvr = HuCPU.timer_value;
if(HuCPU.timer_next_timestamp == HuCPU.timestamp)
tvr = (tvr - 1) & 0x7F;
return(tvr | (PCEIODataBuffer & 0x80));
}
static INLINE void HuC6280_TimerWrite(unsigned int A, uint8 V)
{
switch(A & 1)
{
case 0: HuCPU.timer_load = (V & 0x7F); break;
case 1: if(V & 1) // Enable counter
{
if(HuCPU.timer_status == 0)
{
HuCPU.timer_next_timestamp = HuCPU.timestamp + 1024;
HuCPU.timer_value = HuCPU.timer_load;
}
}
HuCPU.timer_status = V & 1;
break;
}
}
static INLINE uint8 HuC6280_IRQStatusRead(unsigned int A)
{
if(!(A & 2))
return(PCEIODataBuffer);
switch(A & 1)
{
case 0:
HuC6280_IRQEnd(MDFN_IQTIMER);
return(HuCPU.IRQMask ^ 0x7);
case 1:
{
int status = 0;
if(HuCPU.IRQlow & MDFN_IQIRQ1) status |= 2;
if(HuCPU.IRQlow & MDFN_IQIRQ2) status |= 1;
if(HuCPU.IRQlow & MDFN_IQTIMER) status |= 4;
return(status | (PCEIODataBuffer & ~(1 | 2 | 4)));
}
}
return(PCEIODataBuffer);
}
static INLINE void HuC6280_IRQStatusWrite(unsigned int A, uint8 V)
{
if(!(A & 2)) return;
switch(A & 1)
{
case 0: HuCPU.IRQMask = (V & 0x7) ^ 0x7; break;
case 1: HuC6280_IRQEnd(MDFN_IQTIMER); break;
}
}
#define _HuC6280H
#endif

View File

@ -0,0 +1,48 @@
/* 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 "pce.h"
/*
Startup:
0x80 -> $1830
0x40 -> $1823
0x50 -> $1823
0x02 -> $1821
0x40 -> $1823
Read from $1822 16 times, expecting (return value & 0xC0) == 0x80 each time
0x50 -> $1823
0x01 -> $1821
0x40 -> $1823
0x04 -> $1822
*/
DECLFR(PCE_TsushinRead)
{
printf("Read: %04x\n", A);
return(0x80);
}
DECLFW(PCE_TsushinWrite)
{
printf("Write: %04x %02x\n", A, V);
}

View File

@ -0,0 +1,7 @@
#ifndef __PCE_TSUSHIN_H
#define __PCE_TSUSHIN_H
DECLFR(PCE_TsushinRead);
DECLFW(PCE_TsushinWrite);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,206 @@
#ifndef _PCE_VDC_H
#define _PCE_VDC_H
#define REGSETP(_reg, _data, _msb) { _reg &= 0xFF << ((_msb) ? 0 : 8); _reg |= (_data) << ((_msb) ? 8 : 0); }
#define REGGETP(_reg, _msb) ((_reg >> ((_msb) ? 8 : 0)) & 0xFF)
#define VDC_DEBUG(x)
//printf("%s: %d\n", x, vdc->display_counter);
#define VDC_UNDEFINED(x) { }
//{ printf("%s: %d\n", x, vdc->display_counter); }
static const unsigned int vram_inc_tab[4] = { 1, 32, 64, 128 };
typedef struct
{
uint8 priority[2];
uint16 winwidths[2];
uint8 st_mode;
} vpc_t;
extern vpc_t vpc;
static const int VRAM_Size = 0x8000;
static const int VRAM_SizeMask = VRAM_Size - 1; //0x7FFF;
static const int VRAM_BGTileNoMask = VRAM_SizeMask / 16; //0x7FF;
typedef struct
{
uint8 CR;
bool lc263; // 263 line count if set, 262 if not
bool bw; // Black and White
uint8 dot_clock; // Dot Clock(5, 7, or 10 MHz = 0, 1, 2)
uint16 color_table[0x200];
uint32 color_table_cache[0x200];
uint16 ctaddress;
} vce_t;
extern vce_t vce;
typedef struct
{
int16 y;
uint16 height;
uint16 x;
uint16 no;
uint16 flags;
bool cgmode;
} SAT_Cache_t;
typedef struct
{
uint32 display_counter;
int32 sat_dma_slcounter;
uint8 select;
uint16 MAWR; // Memory Address Write Register
uint16 MARR; // Memory Address Read Register
uint16 CR; // Control Register
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 SATB;
uint32 RCRCount;
uint16 read_buffer;
uint8 write_latch;
uint8 status;
uint16 DMAReadBuffer;
bool DMAReadWrite;
bool DMARunning;
bool SATBPending;
bool burst_mode;
uint32 BG_YOffset;
uint32 BG_XOffset;
int SAT_Cache_Valid; // 64 through 128, depending on the number of 32-pixel-wide sprites.
SAT_Cache_t SAT_Cache[128]; //64];
uint16 SAT[0x100];
uint16 VRAM[65536]; //VRAM_Size];
uint64 bg_tile_cache[65536][8]; // Tile, y, x
uint8 spr_tile_cache[1024][16][16]; // Tile, y, x
uint8 spr_tile_clean[1024]; //VRAM_Size / 64];
} vdc_t;
extern vdc_t *vdc_chips[2];
extern int VDC_TotalChips;
void VDC_SetPixelFormat(const MDFN_PixelFormat &format);
void VDC_RunFrame(MDFN_Surface *surface, MDFN_Rect *DisplayRect, MDFN_Rect *LineWidths, int skip);
void VDC_SetLayerEnableMask(uint64 mask);
DECLFW(VDC_Write);
DECLFW(VDC_Write_ST);
DECLFR(VCE_Read);
static INLINE uint8 VDC_Read(unsigned int A, bool SGX)
{
uint8 ret = 0;
int msb = A & 1;
int chip = 0;
vdc_t *vdc;
if(SGX)
{
A &= 0x1F;
switch(A)
{
case 0x8: return(vpc.priority[0]);
case 0x9: return(vpc.priority[1]);
case 0xA: return(vpc.winwidths[0]);
case 0xB: return(vpc.winwidths[0] >> 8);
case 0xC: return(vpc.winwidths[1]);
case 0xD: return(vpc.winwidths[1] >> 8);
case 0xE: return(0);
}
if(A & 0x8) return(0);
chip = (A & 0x10) >> 4;
vdc = vdc_chips[chip];
A &= 0x3;
}
else
{
vdc = vdc_chips[0];
A &= 0x3;
}
switch(A)
{
case 0x0: ret = vdc->status;
vdc->status &= ~0x3F;
if(SGX)
{
if(!(vdc_chips[0]->status & 0x3F) && !(vdc_chips[1]->status & 0x3F))
HuC6280_IRQEnd(MDFN_IQIRQ1);
}
else
HuC6280_IRQEnd(MDFN_IQIRQ1); // Clear VDC IRQ line
break;
case 0x2:
case 0x3:
ret = REGGETP(vdc->read_buffer, msb);
if(vdc->select == 0x2) // VRR - VRAM Read Register
{
if(msb)
{
vdc->MARR += vram_inc_tab[(vdc->CR >> 11) & 0x3];
if(vdc->MARR >= VRAM_Size)
VDC_UNDEFINED("Unmapped VRAM VRR read");
vdc->read_buffer = vdc->VRAM[vdc->MARR & VRAM_SizeMask];
}
}
break;
}
//if(HuCPU.isopread && (A == 1 || A == 3)) //(A == 2 || A == 3)) // && A == 1)
if(A == 1)
{
//if(vdc->display_counter >= (VDS + VSW) && vdc->display_counter < (VDS + VSW + VDW + 1) && vce.dot_clock > 0)
if(vce.dot_clock > 0)
ret = 0x40;
//printf("%d %d %02x\n", vdc->display_counter, vce.dot_clock, ret);
//ret = 0x40;
}
return(ret);
}
DECLFW(VCE_Write);
void VDC_Init(int sgx);
void VDC_Close(void);
void VDC_Reset(void);
void VDC_Power(void);
int VDC_StateAction(StateMem *sm, int load, int data_only);
#endif

View File

@ -0,0 +1,35 @@
uint32 vdc2_pixel, vdc1_pixel;
vdc2_pixel = vdc1_pixel = vce.color_table_cache[0];
if(pb & 1)
vdc1_pixel = lb0[x];
if(pb & 2)
vdc2_pixel = lb1[x];
/* Dai MakaiMura uses setting 1, and expects VDC #2 sprites in front of VDC #1 background, but
behind VDC #1's sprites.
*/
switch(pb >> 2)
{
case 1:
//if((vdc2_pixel & (amask << 2)) && !(vdc1_pixel & (amask << 2)))
// vdc1_pixel |= amask;
vdc1_pixel |= (((vdc2_pixel ^ vdc1_pixel) & vdc2_pixel) >> 2) & amask;
break;
case 2:
//if((vdc1_pixel & (amask << 2)) && !(vdc2_pixel & (amask << 2)) && !(vdc2_pixel & amask))
// vdc1_pixel |= amask;
puts("MOO");
// TODO: Verify that this is correct logic.
{
const uint32 intermediate = ((vdc1_pixel ^ vdc2_pixel) & vdc1_pixel) >> 2;
vdc1_pixel |= (intermediate ^ vdc2_pixel) & intermediate & amask;
}
break;
}
target[x] = (vdc1_pixel & amask) ? vdc2_pixel : vdc1_pixel;

View File

@ -33,6 +33,21 @@ bool MDFN_SaveSettings(const char *path)
uint64 MDFN_GetSettingUI(const char *name)
{
/* PCE FAST */
if(!strcmp("pce_fast.cddavolume", name)) /* make configurable */
return 100;
if(!strcmp("pce_fast.adpcmvolume", name)) /* make configurable */
return 100;
if(!strcmp("pce_fast.cdpsgvolume", name)) /* make configurable */
return 100;
if(!strcmp("pce_fast.cdspeed", name)) /* make configurable */
return 1;
if(!strcmp("pce_fast.ocmultiplier", name)) /* make configurable */
return 1;
if(!strcmp("pce_fast.slstart", name))
return 4;
if(!strcmp("pce_fast.slend", name))
return 235;
/* PSX */
if(!strcmp("psx.spu.resamp_quality", name)) /* make configurable */
return 4;
@ -135,7 +150,7 @@ std::string MDFN_GetSettingS(const char *name)
if(!strcmp("pce_fast.cdbios", name))
{
fprintf(stderr, "pce_fast.cdbios: %s\n", std::string("syscard3.pce").c_str());
return std::string("syscard3.pce");
return std::string(retro_base_directory) + std::string("syscard3.pce");
}
/* PSX */
if(!strcmp("psx.bios_eu", name))

View File

@ -1,8 +1,6 @@
#ifndef _STATE_H
#define _STATE_H
#include <zlib.h>
#include "video.h"
#include "state-common.h"
@ -10,8 +8,6 @@ void MDFNSS_GetStateInfo(const char *filename, StateStatusStruct *status);
int MDFNSS_Save(const char *, const char *suffix, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const MDFN_Rect *LineWidths = (MDFN_Rect *)NULL);
int MDFNSS_Load(const char *, const char *suffix);
int MDFNSS_SaveFP(gzFile fp, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const MDFN_Rect *LineWidths = (MDFN_Rect *)NULL);
int MDFNSS_LoadFP(gzFile fp);
typedef struct
{

View File

@ -36,7 +36,11 @@ MDFN_PixelFormat::MDFN_PixelFormat()
MDFN_PixelFormat::MDFN_PixelFormat(const unsigned int p_colorspace, const uint8 p_rs, const uint8 p_gs, const uint8 p_bs, const uint8 p_as)
{
#if defined(WANT_16BPP)
bpp = 16;
#else
bpp = 32;
#endif
colorspace = p_colorspace;
Rshift = p_rs;
@ -121,13 +125,18 @@ void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32
// to boot.
void MDFN_Surface::SetFormat(const MDFN_PixelFormat &nf, bool convert)
{
#if (defined(WANT_PSX_EMU)) && defined(__LIBRETRO__)
#if defined(WANT_32BPP)
assert(format.bpp == 32);
assert(nf.bpp == 32);
assert((nf.Rshift + nf.Gshift + nf.Bshift + nf.Ashift) == 48);
assert(!((nf.Rshift | nf.Gshift | nf.Bshift | nf.Ashift) & 0x7));
format = nf;
#elif defined(WANT_16BPP)
assert(format.bpp == 16);
assert(nf.bpp == 16);
format = nf;
#else
assert(format.bpp == 16 || format.bpp == 32);
@ -266,12 +275,17 @@ void MDFN_Surface::Fill(uint8 r, uint8 g, uint8 b, uint8 a)
{
uint32 color = MakeColor(r, g, b, a);
#if (defined(WANT_PSX_EMU) && defined(__LIBRETRO__))
#if defined(WANT_32BP)
/* 32bpp color */
assert(pixels);
for(int32 i = 0; i < pitchinpix * h; i++)
pixels[i] = color;
#elif defined(WANT_16BPP)
assert(pixels16);
for(int32 i = 0; i < pitchinpix * h; i++)
pixels16[i] = color;
#else
/* 16bpp color */
if(format.bpp == 16)

View File

@ -52,11 +52,16 @@ class MDFN_PixelFormat
uint8 Aprec;
// Creates a color value for the surface corresponding to the 8-bit R/G/B/A color passed.
#if (defined(WANT_PSX_EMU)) && defined(__LIBRETRO__)
#if defined(WANT_32BPP)
INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const
{
return((r << Rshift) | (g << Gshift) | (b << Bshift) | (a << Ashift));
}
#elif defined(WANT_16BPP)
INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const
{
return (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3) << 0));
}
#else
INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const
{
@ -94,7 +99,7 @@ class MDFN_PixelFormat
#endif
// Gets the R/G/B/A values for the passed 32-bit surface pixel value
#if (defined(WANT_PSX_EMU)) && defined(__LIBRETRO__)
#if defined(WANT_32BPP)
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
{
r = (value >> Rshift) & 0xFF;
@ -102,6 +107,13 @@ class MDFN_PixelFormat
b = (value >> Bshift) & 0xFF;
a = (value >> Ashift) & 0xFF;
}
#elif defined(WANT_16BPP)
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
{
r = ((value & 0x1f) << 10) & 0x7fff;
g = (((value & 0x3e0) << 5) <<5) & 0x7fff;
b = (((value & 0x7c00) >> 10)) & 0x7fff;
}
#else
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
{
@ -192,23 +204,48 @@ class MDFN_Surface //typedef struct
void SetFormat(const MDFN_PixelFormat &new_format, bool convert);
// Creates a 32-bit value for the surface corresponding to the R/G/B/A color passed.
#if defined(WANT_16BPP)
INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const
{
return (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3) << 0));
}
#else
INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const
{
return(format.MakeColor(r, g, b, a));
}
#endif
// Gets the R/G/B/A values for the passed 32-bit surface pixel value
#if defined(WANT_16BPP)
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
{
r = ((value & 0x1f) << 10) & 0x7fff;
g = (((value & 0x3e0) << 5) <<5) & 0x7fff;
b = (((value & 0x7c00) >> 10)) & 0x7fff;
}
#else
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
{
format.DecodeColor(value, r, g, b, a);
}
#endif
#if defined(WANT_16BPP)
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const
{
r = ((value & 0x1f) << 10) & 0x7fff;
g = (((value & 0x3e0) << 5) <<5) & 0x7fff;
b = (((value & 0x7c00) >> 10)) & 0x7fff;
}
#else
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const
{
int dummy_a;
DecodeColor(value, r, g, b, dummy_a);
}
#endif
private:
void Init(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf);
};

6
scrc32.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _S_CRC32_H
#define _S_CRC32_H
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len);
#endif

View File

@ -5,6 +5,8 @@
#include "mednafen/general.h"
#include "mednafen/mednafen-driver.h"
#include <unistd.h>
#include <iostream>
#ifdef _WIN32