mirror of
https://github.com/libretro/beetle-pce-fast-libretro.git
synced 2024-11-26 17:40:40 +00:00
Integrated pfce_fast now too - can compile pce_fast now in same
repo
This commit is contained in:
parent
e1b305a8b4
commit
dc4236c507
43
Makefile
43
Makefile
@ -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
|
||||
|
||||
|
79
libretro.cpp
79
libretro.cpp
@ -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;
|
||||
|
@ -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
330
mednafen/hw_cpu/c68k/c68k.c
Normal 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
237
mednafen/hw_cpu/c68k/c68k.h
Normal 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_
|
||||
|
0
mednafen/hw_cpu/c68k/c68k_ini.inc
Normal file
0
mednafen/hw_cpu/c68k/c68k_ini.inc
Normal file
8329
mednafen/hw_cpu/c68k/c68k_op0.inc
Normal file
8329
mednafen/hw_cpu/c68k/c68k_op0.inc
Normal file
File diff suppressed because it is too large
Load Diff
5626
mednafen/hw_cpu/c68k/c68k_op1.inc
Normal file
5626
mednafen/hw_cpu/c68k/c68k_op1.inc
Normal file
File diff suppressed because it is too large
Load Diff
6247
mednafen/hw_cpu/c68k/c68k_op2.inc
Normal file
6247
mednafen/hw_cpu/c68k/c68k_op2.inc
Normal file
File diff suppressed because it is too large
Load Diff
6247
mednafen/hw_cpu/c68k/c68k_op3.inc
Normal file
6247
mednafen/hw_cpu/c68k/c68k_op3.inc
Normal file
File diff suppressed because it is too large
Load Diff
7141
mednafen/hw_cpu/c68k/c68k_op4.inc
Normal file
7141
mednafen/hw_cpu/c68k/c68k_op4.inc
Normal file
File diff suppressed because it is too large
Load Diff
7801
mednafen/hw_cpu/c68k/c68k_op5.inc
Normal file
7801
mednafen/hw_cpu/c68k/c68k_op5.inc
Normal file
File diff suppressed because it is too large
Load Diff
4434
mednafen/hw_cpu/c68k/c68k_op6.inc
Normal file
4434
mednafen/hw_cpu/c68k/c68k_op6.inc
Normal file
File diff suppressed because it is too large
Load Diff
2058
mednafen/hw_cpu/c68k/c68k_op7.inc
Normal file
2058
mednafen/hw_cpu/c68k/c68k_op7.inc
Normal file
File diff suppressed because it is too large
Load Diff
5965
mednafen/hw_cpu/c68k/c68k_op8.inc
Normal file
5965
mednafen/hw_cpu/c68k/c68k_op8.inc
Normal file
File diff suppressed because it is too large
Load Diff
5855
mednafen/hw_cpu/c68k/c68k_op9.inc
Normal file
5855
mednafen/hw_cpu/c68k/c68k_op9.inc
Normal file
File diff suppressed because it is too large
Load Diff
4116
mednafen/hw_cpu/c68k/c68k_opA.inc
Normal file
4116
mednafen/hw_cpu/c68k/c68k_opA.inc
Normal file
File diff suppressed because it is too large
Load Diff
5845
mednafen/hw_cpu/c68k/c68k_opB.inc
Normal file
5845
mednafen/hw_cpu/c68k/c68k_opB.inc
Normal file
File diff suppressed because it is too large
Load Diff
5283
mednafen/hw_cpu/c68k/c68k_opC.inc
Normal file
5283
mednafen/hw_cpu/c68k/c68k_opC.inc
Normal file
File diff suppressed because it is too large
Load Diff
5855
mednafen/hw_cpu/c68k/c68k_opD.inc
Normal file
5855
mednafen/hw_cpu/c68k/c68k_opD.inc
Normal file
File diff suppressed because it is too large
Load Diff
6034
mednafen/hw_cpu/c68k/c68k_opE.inc
Normal file
6034
mednafen/hw_cpu/c68k/c68k_opE.inc
Normal file
File diff suppressed because it is too large
Load Diff
4116
mednafen/hw_cpu/c68k/c68k_opF.inc
Normal file
4116
mednafen/hw_cpu/c68k/c68k_opF.inc
Normal file
File diff suppressed because it is too large
Load Diff
167
mednafen/hw_cpu/c68k/c68kexec.c
Normal file
167
mednafen/hw_cpu/c68k/c68kexec.c
Normal 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
|
||||
}
|
||||
|
254
mednafen/hw_cpu/c68k/c68kmac.inc
Normal file
254
mednafen/hw_cpu/c68k/c68kmac.inc
Normal 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) \
|
||||
} \
|
||||
}
|
3780
mednafen/hw_cpu/c68k/gen68k.c
Normal file
3780
mednafen/hw_cpu/c68k/gen68k.c
Normal file
File diff suppressed because it is too large
Load Diff
68
mednafen/hw_cpu/c68k/gen68k.h
Normal file
68
mednafen/hw_cpu/c68k/gen68k.h
Normal 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_
|
||||
|
1649
mednafen/hw_cpu/c68k/gen68k.inc
Normal file
1649
mednafen/hw_cpu/c68k/gen68k.inc
Normal file
File diff suppressed because it is too large
Load Diff
790
mednafen/hw_cpu/huc6280/huc6280.cpp
Normal file
790
mednafen/hw_cpu/huc6280/huc6280.cpp
Normal 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;
|
||||
}
|
||||
}
|
579
mednafen/hw_cpu/huc6280/huc6280.h
Normal file
579
mednafen/hw_cpu/huc6280/huc6280.h
Normal 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
|
95
mednafen/hw_cpu/huc6280/huc6280_step.inc
Normal file
95
mednafen/hw_cpu/huc6280/huc6280_step.inc
Normal 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
|
||||
|
554
mednafen/hw_cpu/huc6280/ops.inc
Normal file
554
mednafen/hw_cpu/huc6280/ops.inc
Normal 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;
|
||||
|
8
mednafen/hw_misc/Makefile.am
Normal file
8
mednafen/hw_misc/Makefile.am
Normal 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
|
||||
|
608
mednafen/hw_misc/Makefile.in
Normal file
608
mednafen/hw_misc/Makefile.in
Normal 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:
|
366
mednafen/hw_misc/arcade_card/arcade_card.cpp
Normal file
366
mednafen/hw_misc/arcade_card/arcade_card.cpp
Normal 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;
|
||||
}
|
||||
|
55
mednafen/hw_misc/arcade_card/arcade_card.h
Normal file
55
mednafen/hw_misc/arcade_card/arcade_card.h
Normal 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
|
862
mednafen/hw_sound/pce_psg/pce_psg.cpp
Normal file
862
mednafen/hw_sound/pce_psg/pce_psg.cpp
Normal 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);
|
||||
}
|
180
mednafen/hw_sound/pce_psg/pce_psg.h
Normal file
180
mednafen/hw_sound/pce_psg/pce_psg.h
Normal 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
|
20
mednafen/hw_sound/ym2413/2413tone.h
Normal file
20
mednafen/hw_sound/ym2413/2413tone.h
Normal 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
|
||||
|
1768
mednafen/hw_sound/ym2413/emu2413.cpp
Normal file
1768
mednafen/hw_sound/ym2413/emu2413.cpp
Normal file
File diff suppressed because it is too large
Load Diff
123
mednafen/hw_sound/ym2413/emu2413.h
Normal file
123
mednafen/hw_sound/ym2413/emu2413.h
Normal 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
|
1950
mednafen/hw_video/huc6270/backup/vdc.cpp
Normal file
1950
mednafen/hw_video/huc6270/backup/vdc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
mednafen/hw_video/huc6270/backup/vdc.h
Normal file
435
mednafen/hw_video/huc6270/backup/vdc.h
Normal 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
|
1953
mednafen/hw_video/huc6270/vdc.cpp
Normal file
1953
mednafen/hw_video/huc6270/vdc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
mednafen/hw_video/huc6270/vdc.h
Normal file
435
mednafen/hw_video/huc6270/vdc.h
Normal 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
|
@ -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[] =
|
||||
|
8
mednafen/pce_fast-0924/Makefile.am
Normal file
8
mednafen/pce_fast-0924/Makefile.am
Normal 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)
|
605
mednafen/pce_fast-0924/Makefile.in
Normal file
605
mednafen/pce_fast-0924/Makefile.in
Normal 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:
|
407
mednafen/pce_fast-0924/huc.cpp
Normal file
407
mednafen/pce_fast-0924/huc.cpp
Normal 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();
|
||||
}
|
12
mednafen/pce_fast-0924/huc.h
Normal file
12
mednafen/pce_fast-0924/huc.h
Normal 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;
|
635
mednafen/pce_fast-0924/huc6280_ops.inc
Normal file
635
mednafen/pce_fast-0924/huc6280_ops.inc
Normal 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;
|
390
mednafen/pce_fast-0924/input.cpp
Normal file
390
mednafen/pce_fast-0924/input.cpp
Normal 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");
|
||||
}
|
28
mednafen/pce_fast-0924/input.h
Normal file
28
mednafen/pce_fast-0924/input.h
Normal 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
|
157
mednafen/pce_fast-0924/input/gamepad.cpp
Normal file
157
mednafen/pce_fast-0924/input/gamepad.cpp
Normal 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));
|
||||
}
|
9
mednafen/pce_fast-0924/input/gamepad.h
Normal file
9
mednafen/pce_fast-0924/input/gamepad.h
Normal 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
|
166
mednafen/pce_fast-0924/input/mouse.cpp
Normal file
166
mednafen/pce_fast-0924/input/mouse.cpp
Normal 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());
|
||||
}
|
8
mednafen/pce_fast-0924/input/mouse.h
Normal file
8
mednafen/pce_fast-0924/input/mouse.h
Normal 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
|
299
mednafen/pce_fast-0924/input/tsushinkb.cpp
Normal file
299
mednafen/pce_fast-0924/input/tsushinkb.cpp
Normal 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());
|
||||
}
|
8
mednafen/pce_fast-0924/input/tsushinkb.h
Normal file
8
mednafen/pce_fast-0924/input/tsushinkb.h
Normal 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
|
163
mednafen/pce_fast-0924/ioread.inc
Normal file
163
mednafen/pce_fast-0924/ioread.inc
Normal 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);
|
650
mednafen/pce_fast-0924/pce.cpp
Normal file
650
mednafen/pce_fast-0924/pce.cpp
Normal 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
|
||||
};
|
35
mednafen/pce_fast-0924/pce.h
Normal file
35
mednafen/pce_fast-0924/pce.h
Normal 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
|
744
mednafen/pce_fast-0924/pce_huc6280.cpp
Normal file
744
mednafen/pce_fast-0924/pce_huc6280.cpp
Normal 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);
|
||||
}
|
147
mednafen/pce_fast-0924/pce_huc6280.h
Normal file
147
mednafen/pce_fast-0924/pce_huc6280.h
Normal 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
|
48
mednafen/pce_fast-0924/tsushin.cpp
Normal file
48
mednafen/pce_fast-0924/tsushin.cpp
Normal 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);
|
||||
}
|
7
mednafen/pce_fast-0924/tsushin.h
Normal file
7
mednafen/pce_fast-0924/tsushin.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef __PCE_TSUSHIN_H
|
||||
#define __PCE_TSUSHIN_H
|
||||
|
||||
DECLFR(PCE_TsushinRead);
|
||||
DECLFW(PCE_TsushinWrite);
|
||||
|
||||
#endif
|
1640
mednafen/pce_fast-0924/vdc.cpp
Normal file
1640
mednafen/pce_fast-0924/vdc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
206
mednafen/pce_fast-0924/vdc.h
Normal file
206
mednafen/pce_fast-0924/vdc.h
Normal 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
|
35
mednafen/pce_fast-0924/vpc_mix_inner.inc
Normal file
35
mednafen/pce_fast-0924/vpc_mix_inner.inc
Normal 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;
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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
6
scrc32.h
Normal 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
|
Loading…
Reference in New Issue
Block a user