[Core/VDP]
--------------- * added support for Master System compatibility mode (Z80 ports access mode), incl. Mode 5 rendering. * added Mode 4 rendering for both Genesis & Master System modes. * added alternate BG planes rendering functions (should be faster on PPC architectures). [Core/IO] --------------- * added support for Master System compatibility mode (Z80 ports access mode). * added Master System peripherals emulation (Control Pad, Paddle, Sports Pad & Light Phaser). * added XE-1AP (analog controller) emulation. * added Activator emulation. [Core/Extra] --------------- * added support for all known Master System cartridge mappers. * added copy-protection hardware emulation for a few MD unlicensed games: fixes 777 Casino (crash when talking to bunny girls). (NB: most of those unlicensed games seem to have been already patched by ROM dumpers, main purpose is documenting them) * added support for Top Shooter arcade board controller. (A=Shoot, B=Bet, C/RIGHT=Coins, START=Start, hold UP on startup to enter service mode) * improved King of Fighters 98 mapper emulation (registers address decoding is now 100% accurate) * fixed Game Genie when several codes affect same ROM address. * fixed EEPROM types for Brian Lara Cricket & NBA Jam TE (verified on real cartridges) [Core/General] --------------- * added Master System compatibility mode emulation (automatically enabled when loading ROM file with .sms extension). * improved savestate stability & compatibility (support for old 1.4.x savestates is preserved) * various code cleanup & comments. [Gamecube/Wii] --------------- * fixed cheat codes handling when several codes affect same ROM address. * improved input controller detection on menu exit. * improved key remapping dialog box to match emulated device * changed Menu key for Gamecube controller to allow MODE button mapping * fixed DVD not being unmounted on swap (memory leak) [Wii only] --------------- * added USB mouse support for Sega Mouse emulation * compiled with latest libogc: improves USB compatibility & fixes stability issues with Wiimotes.
47
HISTORY.txt
@ -1,3 +1,50 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
Genesis Plus GX 1.5.0 (31/03/2011) (Eke-Eke)
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
[Core/VDP]
|
||||
---------------
|
||||
* added support for Master System compatibility mode (Z80 ports access mode), incl. Mode 5 rendering.
|
||||
* added Mode 4 rendering for both Genesis & Master System modes.
|
||||
* added alternate BG planes rendering functions (should be faster on PPC architectures).
|
||||
|
||||
[Core/IO]
|
||||
---------------
|
||||
* added support for Master System compatibility mode (Z80 ports access mode).
|
||||
* added Master System peripherals emulation (Control Pad, Paddle, Sports Pad & Light Phaser).
|
||||
* added XE-1AP (analog controller) emulation.
|
||||
* added Activator emulation.
|
||||
|
||||
[Core/Extra]
|
||||
---------------
|
||||
* added support for all known Master System cartridge mappers.
|
||||
* added copy-protection hardware emulation for a few MD unlicensed games: fixes 777 Casino (crash when talking to bunny girls).
|
||||
(NB: most of those unlicensed games seem to have been already patched by ROM dumpers, main purpose is documenting them)
|
||||
* added support for Top Shooter arcade board controller. (A=Shoot, B=Bet, C/RIGHT=Coins, START=Start, hold UP on startup to enter service mode)
|
||||
* improved King of Fighters 98 mapper emulation (registers address decoding is now 100% accurate)
|
||||
* fixed Game Genie when several codes affect same ROM address.
|
||||
* fixed EEPROM types for Brian Lara Cricket & NBA Jam TE (verified on real cartridges)
|
||||
|
||||
[Core/General]
|
||||
---------------
|
||||
* added Master System compatibility mode emulation (automatically enabled when loading ROM file with .sms extension).
|
||||
* improved savestate stability & compatibility (support for old 1.4.x savestates is preserved)
|
||||
* various code cleanup & comments.
|
||||
|
||||
[Gamecube/Wii]
|
||||
---------------
|
||||
* fixed cheat codes handling when several codes affect same ROM address.
|
||||
* improved input controller detection on menu exit.
|
||||
* improved key remapping dialog box to match emulated device
|
||||
* changed Menu key for Gamecube controller to allow MODE button mapping
|
||||
* fixed DVD not being unmounted on swap (memory leak)
|
||||
|
||||
[Wii only]
|
||||
---------------
|
||||
* added USB mouse support for Sega Mouse emulation
|
||||
* compiled with latest libogc: improves USB compatibility & fixes stability issues with Wiimotes.
|
||||
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
Genesis Plus GX 1.4.1 (04/12/2010) (Eke-Eke)
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
@ -17,9 +17,9 @@ include $(DEVKITPPC)/gamecube_rules
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := genplus_cube
|
||||
BUILD := build_cube
|
||||
SOURCES := source source/m68k source/z80 source/sound source/ntsc source/cart_hw source/cart_hw/svp \
|
||||
SOURCES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cart_hw source/cart_hw/svp \
|
||||
source/gx source/gx/utils source/gx/gui source/gx/fileio source/gx/images source/gx/sounds
|
||||
INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/cart_hw source/cart_hw/svp \
|
||||
INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cart_hw source/cart_hw/svp \
|
||||
source/gx source/gx/utils source/gx/gui source/gx/fileio source/gx/images source/gx/sounds \
|
||||
$(BUILD)
|
||||
|
||||
@ -27,7 +27,7 @@ INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/cart_h
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DWORDS_BIGENDIAN -DNGC -DHW_DOL
|
||||
CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DALT_RENDERER -DNGC -DHW_DOL
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
|
||||
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
|
||||
|
@ -17,9 +17,9 @@ include $(DEVKITPPC)/wii_rules
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := genplus_wii
|
||||
BUILD := build_wii
|
||||
SOURCES := source source/m68k source/z80 source/sound source/ntsc source/cart_hw source/cart_hw/svp \
|
||||
SOURCES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cart_hw source/cart_hw/svp \
|
||||
source/gx source/gx/utils source/gx/gui source/gx/fileio source/gx/images source/gx/sounds
|
||||
INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/cart_hw source/cart_hw/svp \
|
||||
INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cart_hw source/cart_hw/svp \
|
||||
source/gx source/gx/utils source/gx/gui source/gx/fileio source/gx/images source/gx/sounds \
|
||||
$(BUILD)
|
||||
|
||||
@ -27,7 +27,7 @@ INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/cart_h
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DWORDS_BIGENDIAN -DNGC -DHW_RVL
|
||||
CFLAGS = -O3 -fomit-frame-pointer -Wall -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DALT_RENDERER -DNGC -DHW_RVL
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
|
||||
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
|
||||
|
@ -38,10 +38,10 @@ static const T_GAME_ENTRY database[GAME_CNT] =
|
||||
/* 24C02 (old mapper) */
|
||||
{{"T-081326" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200001, 0, 1, 1}}, /* NBA Jam (UE) */
|
||||
{{"T-81033" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200001, 0, 1, 1}}, /* NBA Jam (J) */
|
||||
|
||||
/* 24C02 */
|
||||
{{"T-81406" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NBA Jam TE */
|
||||
{{"T-081276" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NFL Quarterback Club */
|
||||
/* 24C04 */
|
||||
{{"T-81406" }, 0, {8, 0x1FF, 0x1FF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NBA Jam TE */
|
||||
/* 24C16 */
|
||||
{{"T-081586" }, 0, {8, 0x7FF, 0x7FF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NFL Quarterback Club '96 */
|
||||
/* 24C65 */
|
||||
@ -68,9 +68,8 @@ static const T_GAME_ENTRY database[GAME_CNT] =
|
||||
{{"G-4524" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Ninja Burai Densetsu */
|
||||
|
||||
/* CODEMASTERS mapper */
|
||||
/* 24C01 */
|
||||
{{"T-120106"}, 0, {7, 0x7F, 0x7F, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Brian Lara Cricket */
|
||||
/* 24C08 */
|
||||
{{"T-120106" }, 0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Brian Lara Cricket */
|
||||
{{"T-120096" }, 0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines 2 - Turbo Tournament (E) */
|
||||
{{"00000000-00"}, 0x168B, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Military */
|
||||
{{"00000000-00"}, 0xCEE0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Military (Bad)*/
|
||||
|
@ -118,7 +118,7 @@ void ggenie_reset(int hard)
|
||||
|
||||
void ggenie_switch(int enable)
|
||||
{
|
||||
int i,j;
|
||||
int i;
|
||||
if (enable)
|
||||
{
|
||||
/* enable cheats */
|
||||
|
1200
source/cart_hw/md_cart.c
Normal file
75
source/cart_hw/md_cart.h
Normal file
@ -0,0 +1,75 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus
|
||||
* Mega Drive cartridge hardware support
|
||||
*
|
||||
* Copyright (C) 2007-2011 Eke-Eke (GCN/Wii port)
|
||||
*
|
||||
* Lots of protection mechanism have been discovered by Haze
|
||||
* (http://haze.mameworld.info/)
|
||||
*
|
||||
* Realtec mapper has been figured out by TascoDeluxe
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _MD_CART_H_
|
||||
#define _MD_CART_H_
|
||||
|
||||
/* Lock-On cartridge type */
|
||||
#define TYPE_GG 0x01 /* Game Genie */
|
||||
#define TYPE_AR 0x02 /* (Pro) Action Replay */
|
||||
#define TYPE_SK 0x03 /* Sonic & Knuckles */
|
||||
|
||||
/* Special hardware (0x01 reserved for SMS 3-D glasses) */
|
||||
#define HW_J_CART 0x02
|
||||
#define HW_LOCK_ON 0x04
|
||||
|
||||
/* Cartridge extra hardware */
|
||||
typedef struct
|
||||
{
|
||||
uint8 regs[4]; /* internal registers (R/W) */
|
||||
uint32 mask[4]; /* registers address mask */
|
||||
uint32 addr[4]; /* registers address */
|
||||
uint16 realtec; /* realtec mapper */
|
||||
uint16 bankshift; /* cartridge with bankshift mecanism reseted on software reset */
|
||||
unsigned int (*time_r)(unsigned int address); /* !TIME signal ($a130xx) read handler */
|
||||
void (*time_w)(unsigned int address, unsigned int data); /* !TIME signal ($a130xx) write handler */
|
||||
unsigned int (*regs_r)(unsigned int address); /* cart hardware registers read handler */
|
||||
void (*regs_w)(unsigned int address, unsigned int data); /* cart hardware registers write handler */
|
||||
} T_CART_HW;
|
||||
|
||||
/* Cartridge type */
|
||||
typedef struct
|
||||
{
|
||||
uint8 *rom; /* ROM area */
|
||||
uint8 *base; /* ROM base (saved for OS/Cartridge ROM swap) */
|
||||
uint32 romsize; /* ROM size */
|
||||
uint32 mask; /* ROM mask */
|
||||
uint8 special; /* Lock-On, J-Cart or SMS 3-D glasses hardware */
|
||||
T_CART_HW hw; /* Extra mapping hardware */
|
||||
} T_CART;
|
||||
|
||||
/* global variables */
|
||||
extern T_CART cart;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void md_cart_init(void);
|
||||
extern void md_cart_reset(int hard_reset);
|
||||
extern int md_cart_context_save(uint8 *state);
|
||||
extern int md_cart_context_load(uint8 *state, char *version);
|
||||
|
||||
#endif
|
||||
|
||||
|
631
source/cart_hw/sms_cart.c
Normal file
@ -0,0 +1,631 @@
|
||||
|
||||
/****************************************************************************
|
||||
* Genesis Plus
|
||||
* Master System cartridge hardware support
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1998-2007 Charles MacDonald (SMS Plus original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* Most cartridge protections documented by Haze
|
||||
* (http://haze.mameworld.info/)
|
||||
*
|
||||
* Realtec mapper documented by TascoDeluxe
|
||||
*
|
||||
* 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 "shared.h"
|
||||
|
||||
#define MAPPER_NONE (0)
|
||||
#define MAPPER_SEGA (1)
|
||||
#define MAPPER_CODIES (2)
|
||||
#define MAPPER_KOREA (3)
|
||||
#define MAPPER_MSX (4)
|
||||
|
||||
#define GAME_DATABASE_CNT (75)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 crc;
|
||||
uint8 glasses_3d;
|
||||
uint8 peripheral;
|
||||
uint8 mapper;
|
||||
uint8 region;
|
||||
} rominfo_t;
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 fcr[4];
|
||||
uint8 mapper;
|
||||
} slot;
|
||||
|
||||
/* SMS game database */
|
||||
static const rominfo_t game_list[GAME_DATABASE_CNT] =
|
||||
{
|
||||
/* games requiring CODEMASTER mapper (NOTE: extended video modes don't work on Genesis VDP !) */
|
||||
{0x29822980, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_EUROPE}, /* Cosmic Spacehead */
|
||||
{0xA577CE46, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_EUROPE}, /* Micro Machines */
|
||||
{0xF7C524F6, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_EUROPE}, /* Micro Machines [BAD DUMP] */
|
||||
{0xDBE8895C, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_EUROPE}, /* Micro Machines 2 - Turbo Tournament */
|
||||
{0xC1756BEE, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_EUROPE}, /* Pete Sampras Tennis */
|
||||
{0x8813514B, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_EUROPE}, /* Excellent Dizzy Collection, The [Proto] */
|
||||
{0xEA5C3A6F, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_USA}, /* Dinobasher - Starring Bignose the Caveman [Proto] */
|
||||
{0x152F0DCC, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_USA}, /* Drop Zone" */
|
||||
{0xAA140C9C, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_USA}, /* Excellent Dizzy Collection, The [SMS-GG] */
|
||||
{0xB9664AE1, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_USA}, /* Fantastic Dizzy */
|
||||
{0xC888222B, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_USA}, /* Fantastic Dizzy [SMS-GG] */
|
||||
{0x76C5BDFB, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_USA}, /* Jang Pung 2 [SMS-GG] */
|
||||
{0xD9A7F170, 0, SYSTEM_MS_GAMEPAD, MAPPER_CODIES, REGION_USA}, /* Man Overboard! */
|
||||
|
||||
/* games requiring KOREA mappers (NOTE: TMS9918 video modes don't work on Genesis VDP !) */
|
||||
{0x17AB6883, 0, SYSTEM_MS_GAMEPAD, MAPPER_NONE, REGION_JAPAN_NTSC}, /* FA Tetris (KR) */
|
||||
{0x61E8806F, 0, SYSTEM_MS_GAMEPAD, MAPPER_NONE, REGION_JAPAN_NTSC}, /* Flash Point (KR) */
|
||||
{0x445525E2, 0, SYSTEM_MS_GAMEPAD, MAPPER_MSX, REGION_JAPAN_NTSC}, /* Penguin Adventure (KR) */
|
||||
{0x83F0EEDE, 0, SYSTEM_MS_GAMEPAD, MAPPER_MSX, REGION_JAPAN_NTSC}, /* Street Master (KR) */
|
||||
{0xA05258F5, 0, SYSTEM_MS_GAMEPAD, MAPPER_MSX, REGION_JAPAN_NTSC}, /* Won-Si-In (KR) */
|
||||
{0x06965ED9, 0, SYSTEM_MS_GAMEPAD, MAPPER_MSX, REGION_JAPAN_NTSC}, /* F-1 Spirit - The way to Formula-1 (KR) */
|
||||
{0x89B79E77, 0, SYSTEM_MS_GAMEPAD, MAPPER_KOREA, REGION_JAPAN_NTSC}, /* Dodgeball King (KR) */
|
||||
{0x18FB98A3, 0, SYSTEM_MS_GAMEPAD, MAPPER_KOREA, REGION_JAPAN_NTSC}, /* Jang Pung 3 (KR) */
|
||||
{0x97D03541, 0, SYSTEM_MS_GAMEPAD, MAPPER_KOREA, REGION_JAPAN_NTSC}, /* Sangokushi 3 (KR)"} */
|
||||
{0x67C2F0FF, 0, SYSTEM_MS_GAMEPAD, MAPPER_KOREA, REGION_JAPAN_NTSC}, /* Super Boy 2 (KR) */
|
||||
|
||||
/* games requiring PAL timings */
|
||||
{0x72420F38, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Addams Familly */
|
||||
{0x2D48C1D3, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Back to the Future Part III */
|
||||
{0x1CBB7BF1, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Battlemaniacs (BR) */
|
||||
{0x1B10A951, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Bram Stoker's Dracula */
|
||||
{0xC0E25D62, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* California Games II */
|
||||
{0x45C50294, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Jogos de Verao II (BR) */
|
||||
{0xC9DBF936, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Home Alone */
|
||||
{0x0047B615, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Predator2 */
|
||||
{0xF42E145C, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Quest for the Shaven Yak Starring Ren Hoek & Stimpy (BR) */
|
||||
{0x9F951756, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* RoboCop 3 */
|
||||
{0xF8176918, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Sensible Soccer */
|
||||
{0x1575581D, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Shadow of the Beast */
|
||||
{0x96B3F29E, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Sonic Blast (BR) */
|
||||
{0x5B3B922C, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Sonic the Hedgehog 2 [V0] */
|
||||
{0xD6F2BFCA, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Sonic the Hedgehog 2 [V1] */
|
||||
{0xCA1D3752, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Space Harrier [50 Hz] */
|
||||
{0x85CFC9C9, 0, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_EUROPE}, /* Taito Chase H.Q. */
|
||||
|
||||
/* games requiring 3-D Glasses */
|
||||
{0x871562b0, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_JAPAN_NTSC}, /* Maze Walker */
|
||||
{0x156948f9, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_JAPAN_NTSC}, /* Space Harrier 3-D (J) */
|
||||
{0x6BD5C2BF, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Space Harrier 3-D */
|
||||
{0x8ECD201C, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Blade Eagle 3-D */
|
||||
{0xFBF96C81, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Blade Eagle 3-D (BR) */
|
||||
{0x58D5FC48, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Blade Eagle 3-D [Proto] */
|
||||
{0x31B8040B, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Maze Hunter 3-D */
|
||||
{0xABD48AD2, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Poseidon Wars 3-D */
|
||||
{0xA3EF13CB, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Zaxxon 3-D */
|
||||
{0xBBA74147, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Zaxxon 3-D [Proto] */
|
||||
{0xD6F43DDA, 1, SYSTEM_MS_GAMEPAD, MAPPER_SEGA, REGION_USA}, /* Out Run 3-D */
|
||||
|
||||
/* games requiring 3-D Glasses & Sega Light Phaser */
|
||||
{0xFBE5CFBB, 1, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Missile Defense 3D */
|
||||
{0xE79BB689, 1, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Missile Defense 3D [BIOS] */
|
||||
|
||||
/* games requiring Sega Light Phaser */
|
||||
{0x861B6E79, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Assault City [Light Phaser] */
|
||||
{0x5FC74D2A, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Gangster Town */
|
||||
{0xE167A561, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Hang-On / Safari Hunt */
|
||||
{0xC5083000, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Hang-On / Safari Hunt [BAD DUMP] */
|
||||
{0x91E93385, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Hang-On / Safari Hunt [BIOS] */
|
||||
{0xE8EA842C, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Marksman Shooting / Trap Shooting */
|
||||
{0xE8215C2E, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Marksman Shooting / Trap Shooting / Safari Hunt */
|
||||
{0x205CAAE8, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Operation Wolf (can be played with gamepad in port B)*/
|
||||
{0x23283F37, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Operation Wolf [A] (can be played with gamepad in port B) */
|
||||
{0xDA5A7013, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Rambo 3 */
|
||||
{0x79AC8E7F, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Rescue Mission */
|
||||
{0x4B051022, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Shooting Gallery */
|
||||
{0xA908CFF5, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Spacegun */
|
||||
{0x5359762D, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Wanted */
|
||||
{0x0CA95637, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, REGION_USA}, /* Laser Ghost */
|
||||
|
||||
/* games requiring Sega Paddle */
|
||||
{0xF9DBB533, 0, SYSTEM_PADDLE, MAPPER_SEGA, REGION_JAPAN_NTSC}, /* Alex Kidd BMX Trial */
|
||||
{0xA6FA42D0, 0, SYSTEM_PADDLE, MAPPER_SEGA, REGION_JAPAN_NTSC}, /* Galactic Protector */
|
||||
{0x29BC7FAD, 0, SYSTEM_PADDLE, MAPPER_SEGA, REGION_JAPAN_NTSC}, /* Megumi Rescue */
|
||||
{0x315917D4, 0, SYSTEM_PADDLE, MAPPER_SEGA, REGION_JAPAN_NTSC}, /* Woody Pop */
|
||||
|
||||
/* games requiring Sega Sport Pad */
|
||||
{0x0CB7E21F, 0, SYSTEM_SPORTSPAD, MAPPER_SEGA, REGION_USA}, /* Great Ice Hockey */
|
||||
{0xE42E4998, 0, SYSTEM_SPORTSPAD, MAPPER_SEGA, REGION_USA}, /* Sports Pad Football */
|
||||
{0x41C948BF, 0, SYSTEM_SPORTSPAD, MAPPER_SEGA, REGION_USA} /* Sports Pad Soccer */
|
||||
};
|
||||
|
||||
/* 1K trash buffer */
|
||||
static uint8 dummy[0x400];
|
||||
|
||||
/* Function prorotypes */
|
||||
static void mapper_8k_w(int offset, unsigned int data);
|
||||
static void mapper_16k_w(int offset, unsigned int data);
|
||||
static void write_mapper_none(unsigned int address, unsigned char data);
|
||||
static void write_mapper_sega(unsigned int address, unsigned char data);
|
||||
static void write_mapper_codies(unsigned int address, unsigned char data);
|
||||
static void write_mapper_korea(unsigned int address, unsigned char data);
|
||||
static void write_mapper_msx(unsigned int address, unsigned char data);
|
||||
|
||||
|
||||
void sms_cart_init(void)
|
||||
{
|
||||
/* default mapper */
|
||||
slot.mapper = MAPPER_SEGA;
|
||||
|
||||
/* default supported peripheral */
|
||||
uint8 device = SYSTEM_MS_GAMEPAD;
|
||||
cart.special = 0;
|
||||
|
||||
/* compute CRC */
|
||||
uint32 crc = crc32(0, cart.rom, cart.romsize);
|
||||
|
||||
/* detect cartridge mapper */
|
||||
int i;
|
||||
for (i=0; i<GAME_DATABASE_CNT; i++)
|
||||
{
|
||||
if (crc == game_list[i].crc)
|
||||
{
|
||||
cart.special = game_list[i].glasses_3d;
|
||||
slot.mapper = game_list[i].mapper;
|
||||
device = game_list[i].peripheral;
|
||||
i = GAME_DATABASE_CNT;
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize Z80 write handler */
|
||||
switch(slot.mapper)
|
||||
{
|
||||
case MAPPER_NONE:
|
||||
z80_writemem = write_mapper_none;
|
||||
break;
|
||||
|
||||
case MAPPER_CODIES:
|
||||
z80_writemem = write_mapper_codies;
|
||||
break;
|
||||
|
||||
case MAPPER_KOREA:
|
||||
z80_writemem = write_mapper_korea;
|
||||
break;
|
||||
|
||||
case MAPPER_MSX:
|
||||
z80_writemem = write_mapper_msx;
|
||||
break;
|
||||
|
||||
default:
|
||||
z80_writemem = write_mapper_sega;
|
||||
break;
|
||||
}
|
||||
|
||||
/* initialize default SRAM (32K max.) */
|
||||
sram_init();
|
||||
|
||||
/* restore previous input settings */
|
||||
if (old_system[0] != -1)
|
||||
{
|
||||
input.system[0] = old_system[0];
|
||||
}
|
||||
if (old_system[1] != -1)
|
||||
{
|
||||
input.system[1] = old_system[1];
|
||||
}
|
||||
|
||||
/* default gun offset */
|
||||
input.x_offset = 20;
|
||||
input.y_offset = 0;
|
||||
|
||||
/* detect if game requires specific peripheral */
|
||||
if (device != SYSTEM_MS_GAMEPAD)
|
||||
{
|
||||
/* save port A setting */
|
||||
if (old_system[0] == -1)
|
||||
{
|
||||
old_system[0] = input.system[0];
|
||||
}
|
||||
|
||||
/* force port A configuration */
|
||||
input.system[0] = device;
|
||||
|
||||
/* SpaceGun & Gangster Town use different gun offset */
|
||||
if ((crc == 0x5359762D) || (crc == 0x5FC74D2A))
|
||||
{
|
||||
input.x_offset = 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sms_cart_reset(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Unmapped memory return $FF */
|
||||
memset(dummy, 0xFF, 0x400);
|
||||
|
||||
/* Reset Z80 memory mapping at $0000-$BFFF (first 32k of ROM mirrored) */
|
||||
for(i = 0x00; i < 0x30; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(i & 0x1F) << 10];
|
||||
z80_writemap[i] = dummy;
|
||||
}
|
||||
|
||||
/* Reset Z80 memory mapping at $C000-$FFFF (first 8K of 68k RAM mirrored) */
|
||||
for(i = 0x30; i < 0x40; i++)
|
||||
{
|
||||
z80_readmap[i] = z80_writemap[i] = &work_ram[(i & 0x07) << 10];
|
||||
}
|
||||
|
||||
/* Reset cartridge paging registers */
|
||||
switch(slot.mapper)
|
||||
{
|
||||
case MAPPER_NONE:
|
||||
case MAPPER_SEGA:
|
||||
{
|
||||
slot.fcr[0] = 0;
|
||||
slot.fcr[1] = 0;
|
||||
slot.fcr[2] = 1;
|
||||
slot.fcr[3] = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
slot.fcr[0] = 0;
|
||||
slot.fcr[1] = 0;
|
||||
slot.fcr[2] = 1;
|
||||
slot.fcr[3] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set default memory map */
|
||||
if (slot.mapper != MAPPER_MSX)
|
||||
{
|
||||
mapper_16k_w(0,slot.fcr[0]);
|
||||
mapper_16k_w(1,slot.fcr[1]);
|
||||
mapper_16k_w(2,slot.fcr[2]);
|
||||
mapper_16k_w(3,slot.fcr[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mapper_8k_w(0,slot.fcr[0]);
|
||||
mapper_8k_w(1,slot.fcr[1]);
|
||||
mapper_8k_w(2,slot.fcr[2]);
|
||||
mapper_8k_w(3,slot.fcr[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void sms_cart_switch(int enabled)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
/* Enable cartdige ROM at $0000-$BFFF */
|
||||
for(i = 0x00; i < 0x30; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(i & 0x1F) << 10];
|
||||
z80_writemap[i] = dummy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable cartridge ROM at $0000-$BFFF */
|
||||
for(i = 0x00; i < 0x30; i++)
|
||||
{
|
||||
z80_readmap[i] = z80_writemap[i] = dummy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sms_cart_region_detect(void)
|
||||
{
|
||||
/* compute CRC */
|
||||
uint32 crc = crc32(0, cart.rom, cart.romsize);
|
||||
|
||||
/* detect game region */
|
||||
int i;
|
||||
for (i=0; i<GAME_DATABASE_CNT; i++)
|
||||
{
|
||||
if (crc == game_list[i].crc)
|
||||
{
|
||||
return game_list[i].region;
|
||||
}
|
||||
}
|
||||
|
||||
/* default region */
|
||||
return REGION_USA;
|
||||
}
|
||||
|
||||
int sms_cart_context_save(uint8 *state)
|
||||
{
|
||||
int bufferptr = 0;
|
||||
save_param(slot.fcr, sizeof(slot.fcr));
|
||||
return bufferptr;
|
||||
}
|
||||
|
||||
int sms_cart_context_load(uint8 *state, char *version)
|
||||
{
|
||||
int bufferptr = 0;
|
||||
load_param(slot.fcr, sizeof(slot.fcr));
|
||||
|
||||
/* Set default memory map */
|
||||
if (slot.mapper != MAPPER_MSX)
|
||||
{
|
||||
mapper_16k_w(0,slot.fcr[0]);
|
||||
mapper_16k_w(1,slot.fcr[1]);
|
||||
mapper_16k_w(2,slot.fcr[2]);
|
||||
mapper_16k_w(3,slot.fcr[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mapper_8k_w(0,slot.fcr[0]);
|
||||
mapper_8k_w(1,slot.fcr[1]);
|
||||
mapper_8k_w(2,slot.fcr[2]);
|
||||
mapper_8k_w(3,slot.fcr[3]);
|
||||
}
|
||||
|
||||
return bufferptr;
|
||||
}
|
||||
|
||||
|
||||
void mapper_8k_w(int offset, unsigned int data)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* cartridge ROM page (8k) */
|
||||
uint8 page = data % (cart.romsize >> 13);
|
||||
|
||||
/* Save frame control register data */
|
||||
slot.fcr[offset] = data;
|
||||
|
||||
/* 4 x 8k banks */
|
||||
switch (offset & 3)
|
||||
{
|
||||
case 0: /* cartridge ROM bank (8k) at $8000-$9FFF */
|
||||
{
|
||||
for(i = 0x20; i < 0x28; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 13) | ((i & 0x07) << 10)];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: /* cartridge ROM bank (8k) at $A000-$BFFF */
|
||||
{
|
||||
for(i = 0x28; i < 0x30; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 13) | ((i & 0x07) << 10)];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: /* cartridge ROM bank (8k) at $4000-$5FFF */
|
||||
{
|
||||
for(i = 0x10; i < 0x18; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 13) | ((i & 0x07) << 10)];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: /* cartridge ROM bank (8k) at $6000-$7FFF */
|
||||
{
|
||||
for(i = 0x18; i < 0x20; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 13) | ((i & 0x07) << 10)];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mapper_16k_w(int offset, unsigned int data)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* cartridge ROM page (16k) */
|
||||
uint8 page = data % (cart.romsize >> 14);
|
||||
|
||||
/* page index increment (SEGA mapper) */
|
||||
if (slot.fcr[0] & 0x03)
|
||||
{
|
||||
page = (page + ((4 - (slot.fcr[0] & 0x03)) << 3)) % (cart.romsize >> 14);
|
||||
}
|
||||
|
||||
/* save frame control register data */
|
||||
slot.fcr[offset] = data;
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
case 0: /* control register (SEGA mapper) */
|
||||
{
|
||||
if(data & 0x08)
|
||||
{
|
||||
/* external RAM (upper or lower 16K) mapped at $8000-$BFFF */
|
||||
for(i = 0x20; i <= 0x2F; i++)
|
||||
{
|
||||
z80_readmap[i] = z80_writemap[i] = &sram.sram[((data & 0x04) << 12) + ((i & 0x0F) << 10)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* cartridge ROM page (16k) */
|
||||
page = slot.fcr[3] % (cart.romsize >> 14);
|
||||
|
||||
/* page index increment (SEGA mapper) */
|
||||
if (data & 0x03)
|
||||
{
|
||||
page = (page + ((4 - (data & 0x03)) << 3)) % (cart.romsize >> 14);
|
||||
}
|
||||
|
||||
/* cartridge ROM mapped at $8000-$BFFF */
|
||||
for(i = 0x20; i < 0x30; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 14) | ((i & 0x0F) << 10)];
|
||||
z80_writemap[i] = dummy;
|
||||
}
|
||||
}
|
||||
|
||||
if(data & 0x10)
|
||||
{
|
||||
/* external RAM (lower 16K) mapped at $C000-$FFFF */
|
||||
for(i = 0x30; i < 0x40; i++)
|
||||
{
|
||||
z80_readmap[i] = z80_writemap[i] = &sram.sram[(i & 0x0F) << 10];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* internal RAM (8K mirrorred) mapped at $C000-$FFFF */
|
||||
for(i = 0x30; i < 0x40; i++)
|
||||
{
|
||||
z80_readmap[i] = z80_writemap[i] = &work_ram[(i & 0x07) << 10];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: /* cartridge ROM bank (16k) at $0000-$3FFF */
|
||||
{
|
||||
/* first 1k is not fixed (CODEMASTER mapper) */
|
||||
if (slot.mapper == MAPPER_CODIES)
|
||||
{
|
||||
z80_readmap[0] = &cart.rom[(page << 14)];
|
||||
}
|
||||
|
||||
for(i = 0x01; i < 0x10; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 14) | ((i & 0x0F) << 10)];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: /* cartridge ROM bank (16k) at $4000-$7FFF */
|
||||
{
|
||||
for(i = 0x10; i < 0x20; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 14) | ((i & 0x0F) << 10)];
|
||||
}
|
||||
|
||||
/* Ernie Elf's Golf external RAM switch */
|
||||
if (slot.mapper == MAPPER_CODIES)
|
||||
{
|
||||
if (data & 0x80)
|
||||
{
|
||||
/* external RAM (8k) mapped at $A000-$BFFF */
|
||||
for(i = 0x28; i < 0x30; i++)
|
||||
{
|
||||
z80_readmap[i] = z80_writemap[i] = &sram.sram[(i & 0x0F) << 10];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* cartridge ROM page (16k) */
|
||||
page = slot.fcr[3] % (cart.romsize >> 14);
|
||||
|
||||
/* cartridge ROM mapped at $A000-$BFFF */
|
||||
for(i = 0x28; i < 0x30; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 14) | ((i & 0x0F) << 10)];
|
||||
z80_writemap[i] = dummy;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: /* cartridge ROM bank (16k) at $8000-$BFFF */
|
||||
{
|
||||
/* check that external RAM (16k) is not mapped at $8000-$BFFF (SEGA mapper) */
|
||||
if ((slot.fcr[0] & 0x08)) break;
|
||||
|
||||
/* first 8k */
|
||||
for(i = 0x20; i < 0x28; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 14) | ((i & 0x0F) << 10)];
|
||||
}
|
||||
|
||||
/* check that external RAM (8k) is not mapped at $A000-$BFFF (CODEMASTER mapper) */
|
||||
if ((slot.mapper == MAPPER_CODIES) && (slot.fcr[2] & 0x80)) break;
|
||||
|
||||
/* last 8k */
|
||||
for(i = 0x28; i < 0x30; i++)
|
||||
{
|
||||
z80_readmap[i] = &cart.rom[(page << 14) | ((i & 0x0F) << 10)];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write_mapper_none(unsigned int address, unsigned char data)
|
||||
{
|
||||
z80_writemap[address >> 10][address & 0x03FF] = data;
|
||||
}
|
||||
|
||||
static void write_mapper_sega(unsigned int address, unsigned char data)
|
||||
{
|
||||
if(address >= 0xFFFC)
|
||||
{
|
||||
mapper_16k_w(address & 3, data);
|
||||
}
|
||||
|
||||
z80_writemap[address >> 10][address & 0x03FF] = data;
|
||||
}
|
||||
|
||||
static void write_mapper_codies(unsigned int address, unsigned char data)
|
||||
{
|
||||
if (address == 0x0000)
|
||||
{
|
||||
mapper_16k_w(1,data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (address == 0x4000)
|
||||
{
|
||||
mapper_16k_w(2,data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (address == 0x8000)
|
||||
{
|
||||
mapper_16k_w(3,data);
|
||||
return;
|
||||
}
|
||||
|
||||
z80_writemap[address >> 10][address & 0x03FF] = data;
|
||||
}
|
||||
|
||||
static void write_mapper_korea(unsigned int address, unsigned char data)
|
||||
{
|
||||
if (address == 0xA000)
|
||||
{
|
||||
mapper_16k_w(3,data);
|
||||
return;
|
||||
}
|
||||
|
||||
z80_writemap[address >> 10][address & 0x03FF] = data;
|
||||
}
|
||||
|
||||
static void write_mapper_msx(unsigned int address, unsigned char data)
|
||||
{
|
||||
if (address <= 0x0003)
|
||||
{
|
||||
mapper_8k_w(address,data);
|
||||
return;
|
||||
}
|
||||
|
||||
z80_writemap[address >> 10][address & 0x03FF] = data;
|
||||
}
|
38
source/cart_hw/sms_cart.h
Normal file
@ -0,0 +1,38 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus
|
||||
* Master System cartridge hardware support
|
||||
*
|
||||
* Copyright (C) 1998-2007 Charles MacDonald (SMS Plus original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* Realtec mapper has been figured out by TascoDeluxe
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _SMS_CART_H_
|
||||
#define _SMS_CART_H_
|
||||
|
||||
/* Function prototypes */
|
||||
extern void sms_cart_init(void);
|
||||
extern void sms_cart_reset(void);
|
||||
extern void sms_cart_switch(int enabled);
|
||||
extern int sms_cart_region_detect(void);
|
||||
extern int sms_cart_context_save(uint8 *state);
|
||||
extern int sms_cart_context_load(uint8 *state, char *version);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -59,7 +59,9 @@ void sram_init()
|
||||
|
||||
/* fixe some bad header informations */
|
||||
if ((sram.start > sram.end) || ((sram.end - sram.start) >= 0x10000))
|
||||
{
|
||||
sram.end = sram.start + 0xffff;
|
||||
}
|
||||
sram.start &= 0xfffffffe;
|
||||
sram.end |= 1;
|
||||
|
||||
|
281
source/genesis.c
@ -1,9 +1,9 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Genesis internals & Bus controller
|
||||
* Internal Hardware & Bus controllers
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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
|
||||
@ -42,16 +42,18 @@ void gen_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* initialize CPUs */
|
||||
/* initialize 68k */
|
||||
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
||||
m68k_init();
|
||||
|
||||
/* initialize Z80 */
|
||||
z80_init(0,z80_irq_callback);
|
||||
|
||||
/* initialize 68k mapped memory */
|
||||
/* $000000-$7fffff is affected to cartridge area (see cart_hw.c) */
|
||||
/* $800000-$ffffff is affected to WRAM (see VDP DMA) */
|
||||
/* initialize 68k memory map */
|
||||
/* $000000-$7FFFFF is affected to cartridge area (see md_cart.c) */
|
||||
for (i=0x80; i<0x100; i++)
|
||||
{
|
||||
/* $800000-$FFFFFF is affected to WRAM (see VDP DMA) */
|
||||
m68k_memory_map[i].base = work_ram;
|
||||
m68k_memory_map[i].read8 = NULL;
|
||||
m68k_memory_map[i].read16 = NULL;
|
||||
@ -64,7 +66,7 @@ void gen_init(void)
|
||||
/* initialize 68k memory handlers */
|
||||
for (i=0x80; i<0xe0; i++)
|
||||
{
|
||||
/* illegal area */
|
||||
/* $800000-$DFFFFF : illegal area by default */
|
||||
m68k_memory_map[i].read8 = m68k_lockup_r_8;
|
||||
m68k_memory_map[i].read16 = m68k_lockup_r_16;
|
||||
m68k_memory_map[i].write8 = m68k_lockup_w_8;
|
||||
@ -73,11 +75,7 @@ void gen_init(void)
|
||||
zbank_memory_map[i].write = zbank_lockup_w;
|
||||
}
|
||||
|
||||
/* Z80 bus (bank access) */
|
||||
zbank_memory_map[0xa0].read = zbank_lockup_r;
|
||||
zbank_memory_map[0xa0].write = zbank_lockup_w;
|
||||
|
||||
/* I/O & Control registers */
|
||||
/* $A10000-$A1FFFF : I/O & Control registers */
|
||||
m68k_memory_map[0xa1].read8 = ctrl_io_read_byte;
|
||||
m68k_memory_map[0xa1].read16 = ctrl_io_read_word;
|
||||
m68k_memory_map[0xa1].write8 = ctrl_io_write_byte;
|
||||
@ -85,110 +83,155 @@ void gen_init(void)
|
||||
zbank_memory_map[0xa1].read = zbank_read_ctrl_io;
|
||||
zbank_memory_map[0xa1].write = zbank_write_ctrl_io;
|
||||
|
||||
/* VDP (initially locked on models with TMSS) */
|
||||
if (!(config.tmss & 1))
|
||||
/* $C0xxxx, $C8xxxx, $D0xxxx, $D8xxxx : VDP ports */
|
||||
for (i=0xc0; i<0xe0; i+=8)
|
||||
{
|
||||
for (i=0xc0; i<0xe0; i+=8)
|
||||
{
|
||||
m68k_memory_map[i].read8 = vdp_read_byte;
|
||||
m68k_memory_map[i].read16 = vdp_read_word;
|
||||
m68k_memory_map[i].write8 = vdp_write_byte;
|
||||
m68k_memory_map[i].write16 = vdp_write_word;
|
||||
zbank_memory_map[i].read = zbank_read_vdp;
|
||||
zbank_memory_map[i].write = zbank_write_vdp;
|
||||
}
|
||||
m68k_memory_map[i].read8 = vdp_read_byte;
|
||||
m68k_memory_map[i].read16 = vdp_read_word;
|
||||
m68k_memory_map[i].write8 = vdp_write_byte;
|
||||
m68k_memory_map[i].write16 = vdp_write_word;
|
||||
zbank_memory_map[i].read = zbank_read_vdp;
|
||||
zbank_memory_map[i].write = zbank_write_vdp;
|
||||
}
|
||||
|
||||
/* SEGA PICO */
|
||||
if (system_hw == SYSTEM_PICO)
|
||||
/* MS COMPATIBILITY mode */
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
m68k_memory_map[0x80].read8 = pico_read_byte;
|
||||
m68k_memory_map[0x80].read16 = pico_read_word;
|
||||
m68k_memory_map[0x80].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0x80].write16 = m68k_unused_16_w;
|
||||
/* initialize Z80 read handler */
|
||||
/* NB: memory map & write handler are defined by cartridge hardware */
|
||||
z80_readmem = z80_sms_memory_r;
|
||||
|
||||
/* there is no I/O area (Notaz) */
|
||||
m68k_memory_map[0xa1].read8 = m68k_read_bus_8;
|
||||
m68k_memory_map[0xa1].read16 = m68k_read_bus_16;
|
||||
m68k_memory_map[0xa1].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0xa1].write16 = m68k_unused_16_w;
|
||||
/* initialize Z80 ports handlers */
|
||||
z80_writeport = z80_sms_port_w;
|
||||
z80_readport = z80_sms_port_r;
|
||||
|
||||
/* page registers */
|
||||
pico_current = 0x00;
|
||||
pico_page[0] = 0x00;
|
||||
pico_page[1] = 0x01;
|
||||
pico_page[2] = 0x03;
|
||||
pico_page[3] = 0x07;
|
||||
pico_page[4] = 0x0F;
|
||||
pico_page[5] = 0x1F;
|
||||
pico_page[6] = 0x3F;
|
||||
/* initialize MS cartridge hardware */
|
||||
sms_cart_init();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* PICO hardware */
|
||||
if (system_hw == SYSTEM_PICO)
|
||||
{
|
||||
/* additional registers mapped to $800000-$80FFFF */
|
||||
m68k_memory_map[0x80].read8 = pico_read_byte;
|
||||
m68k_memory_map[0x80].read16 = pico_read_word;
|
||||
m68k_memory_map[0x80].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0x80].write16 = m68k_unused_16_w;
|
||||
|
||||
/* there is no I/O area (Notaz) */
|
||||
m68k_memory_map[0xa1].read8 = m68k_read_bus_8;
|
||||
m68k_memory_map[0xa1].read16 = m68k_read_bus_16;
|
||||
m68k_memory_map[0xa1].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0xa1].write16 = m68k_unused_16_w;
|
||||
|
||||
/* page registers */
|
||||
pico_current = 0x00;
|
||||
pico_page[0] = 0x00;
|
||||
pico_page[1] = 0x01;
|
||||
pico_page[2] = 0x03;
|
||||
pico_page[3] = 0x07;
|
||||
pico_page[4] = 0x0F;
|
||||
pico_page[5] = 0x1F;
|
||||
pico_page[6] = 0x3F;
|
||||
}
|
||||
|
||||
/* initialize Z80 memory map */
|
||||
/* $0000-$3FFF is mapped to Z80 RAM (8K mirrored) */
|
||||
/* $4000-$FFFF is mapped to hardware but Z80.PC should never point there */
|
||||
for (i=0; i<64; i++)
|
||||
{
|
||||
z80_readmap[i] = &zram[(i & 7) << 10];
|
||||
}
|
||||
|
||||
/* initialize Z80 memory handlers */
|
||||
z80_writemem = z80_md_memory_w;
|
||||
z80_readmem = z80_md_memory_r;
|
||||
|
||||
/* initialize Z80 port handlers */
|
||||
z80_writeport = z80_unused_port_w;
|
||||
z80_readport = z80_unused_port_r;
|
||||
|
||||
/* initialize MD cartridge hardware */
|
||||
md_cart_init();
|
||||
}
|
||||
}
|
||||
|
||||
void gen_hardreset(void)
|
||||
void gen_reset(int hard_reset)
|
||||
{
|
||||
/* Clear RAM */
|
||||
memset (work_ram, 0x00, sizeof (work_ram));
|
||||
memset (zram, 0x00, sizeof (zram));
|
||||
|
||||
/* TMSS + OS ROM support */
|
||||
memset(tmss, 0x00, sizeof(tmss));
|
||||
if (config.tmss == 3)
|
||||
/* System Reset */
|
||||
if (hard_reset)
|
||||
{
|
||||
m68k_memory_map[0].base = bios_rom;
|
||||
/* clear RAM */
|
||||
memset (work_ram, 0x00, sizeof (work_ram));
|
||||
memset (zram, 0x00, sizeof (zram));
|
||||
|
||||
/* TMSS & OS ROM support */
|
||||
if (config.tmss & 1)
|
||||
{
|
||||
/* clear TMSS register */
|
||||
memset(tmss, 0x00, sizeof(tmss));
|
||||
|
||||
/* VDP access is locked by default */
|
||||
int i;
|
||||
for (i=0xc0; i<0xe0; i+=8)
|
||||
{
|
||||
m68k_memory_map[i].read8 = m68k_lockup_r_8;
|
||||
m68k_memory_map[i].read16 = m68k_lockup_r_16;
|
||||
m68k_memory_map[i].write8 = m68k_lockup_w_8;
|
||||
m68k_memory_map[i].write16 = m68k_lockup_w_16;
|
||||
zbank_memory_map[i].read = zbank_lockup_r;
|
||||
zbank_memory_map[i].write = zbank_lockup_w;
|
||||
}
|
||||
|
||||
/* OS ROM is mapped at $000000-$0007FF */
|
||||
if (config.tmss & 2)
|
||||
{
|
||||
m68k_memory_map[0].base = bios_rom;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reset YM2612 (on hard reset, this is done by sound_reset) */
|
||||
fm_reset(0);
|
||||
}
|
||||
|
||||
/* 68k & Z80 could restart anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */
|
||||
mcycles_68k = mcycles_z80 = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
|
||||
|
||||
/* Z80 bus is released & Z80 is stopped */
|
||||
zstate = 0;
|
||||
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
|
||||
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
|
||||
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
|
||||
|
||||
/* Assume default bank is $000000-$007FFF */
|
||||
zbank = 0;
|
||||
|
||||
/* Reset 68k & Z80 */
|
||||
m68k_pulse_reset();
|
||||
z80_reset();
|
||||
}
|
||||
|
||||
void gen_softreset(int state)
|
||||
{
|
||||
if (state)
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
/* Halt 68k */
|
||||
/* reset MS cartridge hardware */
|
||||
sms_cart_reset();
|
||||
|
||||
/* Z80 is running */
|
||||
zstate = 1;
|
||||
|
||||
/* 68k is halted */
|
||||
m68k_pulse_halt();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reset MD cartridge hardware */
|
||||
md_cart_reset(hard_reset);
|
||||
|
||||
/* Z80 bus is released & Z80 is reseted */
|
||||
zstate = 0;
|
||||
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
|
||||
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
|
||||
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
|
||||
zstate = 0;
|
||||
|
||||
/* Assume default bank is $000000-$007FFF */
|
||||
/* assume default bank is $000000-$007FFF */
|
||||
zbank = 0;
|
||||
|
||||
/* Reset YM2612 */
|
||||
fm_reset(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset Cartridge Hardware */
|
||||
cart_hw_reset(0);
|
||||
|
||||
/* 68k & Z80 could restart anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */
|
||||
mcycles_68k = mcycles_z80 = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
|
||||
|
||||
/* Reset 68k, Z80 & YM2612 */
|
||||
/* reset 68k */
|
||||
m68k_pulse_reset();
|
||||
z80_reset();
|
||||
fm_reset(0);
|
||||
}
|
||||
|
||||
/* reset Z80 */
|
||||
z80_reset();
|
||||
}
|
||||
|
||||
void gen_shutdown(void)
|
||||
@ -197,16 +240,16 @@ void gen_shutdown(void)
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
OS ROM / TMSS register control functions
|
||||
-----------------------------------------------------------------------*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* OS ROM / TMSS register control functions (Genesis mode) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
void gen_tmss_w(unsigned int offset, unsigned int data)
|
||||
{
|
||||
/* write TMSS regisiter */
|
||||
WRITE_WORD(tmss, offset, data);
|
||||
|
||||
/* VDP requires "SEGA" value to be written in TMSSS register */
|
||||
/* VDP requires "SEGA" value to be written in TMSS register */
|
||||
int i;
|
||||
if (strncmp((char *)tmss, "SEGA", 4) == 0)
|
||||
{
|
||||
@ -236,7 +279,7 @@ void gen_tmss_w(unsigned int offset, unsigned int data)
|
||||
|
||||
void gen_bankswitch_w(unsigned int data)
|
||||
{
|
||||
/* BIOS has not been loaded yet */
|
||||
/* OS ROM has not been loaded yet */
|
||||
if (!(config.tmss & 2))
|
||||
{
|
||||
config.tmss |= 2;
|
||||
@ -262,9 +305,10 @@ unsigned int gen_bankswitch_r(void)
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Z80 Bus controller chip functions
|
||||
-----------------------------------------------------------------------*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Z80 Bus controller chip functions (Genesis mode) */
|
||||
/* ----------------------------------------------------------------------*/
|
||||
|
||||
void gen_zbusreq_w(unsigned int data, unsigned int cycles)
|
||||
{
|
||||
if (data) /* !ZBUSREQ asserted */
|
||||
@ -276,11 +320,10 @@ void gen_zbusreq_w(unsigned int data, unsigned int cycles)
|
||||
z80_run(cycles);
|
||||
|
||||
/* enable 68k access to Z80 bus */
|
||||
_m68k_memory_map *base = &m68k_memory_map[0xa0];
|
||||
base->read8 = z80_read_byte;
|
||||
base->read16 = z80_read_word;
|
||||
base->write8 = z80_write_byte;
|
||||
base->write16 = z80_write_word;
|
||||
m68k_memory_map[0xa0].read8 = z80_read_byte;
|
||||
m68k_memory_map[0xa0].read16 = z80_read_word;
|
||||
m68k_memory_map[0xa0].write8 = z80_write_byte;
|
||||
m68k_memory_map[0xa0].write16 = z80_write_word;
|
||||
}
|
||||
|
||||
/* update Z80 bus status */
|
||||
@ -295,12 +338,11 @@ void gen_zbusreq_w(unsigned int data, unsigned int cycles)
|
||||
mcycles_z80 = cycles;
|
||||
|
||||
/* disable 68k access to Z80 bus */
|
||||
_m68k_memory_map *base = &m68k_memory_map[0xa0];
|
||||
base->read8 = m68k_read_bus_8;
|
||||
base->read16 = m68k_read_bus_16;
|
||||
base->write8 = m68k_unused_8_w;
|
||||
base->write16 = m68k_unused_16_w;
|
||||
}
|
||||
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
|
||||
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
|
||||
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
|
||||
}
|
||||
|
||||
/* update Z80 bus status */
|
||||
zstate &= 1;
|
||||
@ -316,21 +358,20 @@ void gen_zreset_w(unsigned int data, unsigned int cycles)
|
||||
{
|
||||
/* resynchronize with 68k */
|
||||
mcycles_z80 = cycles;
|
||||
|
||||
|
||||
/* reset Z80 & YM2612 */
|
||||
z80_reset();
|
||||
fm_reset(cycles);
|
||||
}
|
||||
|
||||
|
||||
/* check if 68k access to Z80 bus is granted */
|
||||
else if (zstate == 2)
|
||||
{
|
||||
/* enable 68k access to Z80 bus */
|
||||
_m68k_memory_map *base = &m68k_memory_map[0xa0];
|
||||
base->read8 = z80_read_byte;
|
||||
base->read16 = z80_read_word;
|
||||
base->write8 = z80_write_byte;
|
||||
base->write16 = z80_write_word;
|
||||
m68k_memory_map[0xa0].read8 = z80_read_byte;
|
||||
m68k_memory_map[0xa0].read16 = z80_read_word;
|
||||
m68k_memory_map[0xa0].write8 = z80_write_byte;
|
||||
m68k_memory_map[0xa0].write16 = z80_write_word;
|
||||
|
||||
/* reset Z80 & YM2612 */
|
||||
z80_reset();
|
||||
@ -353,11 +394,10 @@ void gen_zreset_w(unsigned int data, unsigned int cycles)
|
||||
else if (zstate == 3)
|
||||
{
|
||||
/* disable 68k access to Z80 bus */
|
||||
_m68k_memory_map *base = &m68k_memory_map[0xa0];
|
||||
base->read8 = m68k_read_bus_8;
|
||||
base->read16 = m68k_read_bus_16;
|
||||
base->write8 = m68k_unused_8_w;
|
||||
base->write16 = m68k_unused_16_w;
|
||||
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
|
||||
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
|
||||
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
|
||||
}
|
||||
|
||||
/* stop YM2612 */
|
||||
@ -373,6 +413,11 @@ void gen_zbank_w (unsigned int data)
|
||||
zbank = ((zbank >> 1) | ((data & 1) << 23)) & 0xFF8000;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Z80 interrupt callback */
|
||||
/* ----------------------------------------------------------------------*/
|
||||
|
||||
int z80_irq_callback (int param)
|
||||
{
|
||||
return 0xFF;
|
||||
|
@ -1,9 +1,9 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Genesis internals & Bus controller
|
||||
* Internal hardware & Bus controllers
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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
|
||||
@ -36,8 +36,7 @@ extern uint8 pico_page[7];
|
||||
|
||||
/* Function prototypes */
|
||||
extern void gen_init(void);
|
||||
extern void gen_hardreset(void);
|
||||
extern void gen_softreset(int state);
|
||||
extern void gen_reset(int hard_reset);
|
||||
extern void gen_shutdown(void);
|
||||
extern void gen_tmss_w(unsigned int offset, unsigned int data);
|
||||
extern void gen_bankswitch_w(unsigned int data);
|
||||
|
@ -55,6 +55,9 @@ static char *fileDir;
|
||||
/* current device */
|
||||
static int deviceType = -1;
|
||||
|
||||
/* DVD status flag */
|
||||
static u8 dvd_mounted = 0;
|
||||
|
||||
/***************************************************************************
|
||||
* MountDVD
|
||||
*
|
||||
@ -64,18 +67,31 @@ static int MountDVD(void)
|
||||
{
|
||||
GUI_MsgBoxOpen("Information", "Mounting DVD ...",1);
|
||||
|
||||
/* check if DVD is already mounted */
|
||||
if (dvd_mounted)
|
||||
{
|
||||
/* unmount DVD */
|
||||
ISO9660_Unmount("dvd:");
|
||||
dvd_mounted = 0;
|
||||
}
|
||||
|
||||
/* check if disc is found */
|
||||
if(!dvd->isInserted())
|
||||
{
|
||||
GUI_WaitPrompt("Error","No Disc inserted !");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!ISO9660_Mount())
|
||||
/* mount DVD */
|
||||
if(!ISO9660_Mount("dvd",dvd))
|
||||
{
|
||||
GUI_WaitPrompt("Error","Disc can not be read !");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* DVD is mounted */
|
||||
dvd_mounted = 1;
|
||||
|
||||
GUI_MsgBoxClose();
|
||||
return 1;
|
||||
}
|
||||
@ -198,7 +214,7 @@ int ParseDirectory(void)
|
||||
* This functions return the actual size of data copied into the buffer
|
||||
*
|
||||
****************************************************************************/
|
||||
int LoadFile(u8 *buffer, u32 selection)
|
||||
int LoadFile(u8 *buffer, u32 selection, char *filename)
|
||||
{
|
||||
char fname[MAXPATHLEN];
|
||||
char *filepath;
|
||||
@ -264,11 +280,14 @@ int LoadFile(u8 *buffer, u32 selection)
|
||||
fread(buffer + done, length, 1, fd);
|
||||
done += length;
|
||||
GUI_MsgBoxClose();
|
||||
|
||||
/* update ROM filename (with extension) */
|
||||
sprintf(filename, "%s", filelist[selection].filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unzip file */
|
||||
done = UnZipBuffer(buffer, fd);
|
||||
done = UnZipBuffer(buffer, fd, filename);
|
||||
}
|
||||
|
||||
/* close file */
|
||||
|
@ -39,6 +39,6 @@
|
||||
extern int OpenDirectory(int device);
|
||||
extern int UpdateDirectory(bool go_up, char *filename);
|
||||
extern int ParseDirectory(void);
|
||||
extern int LoadFile(u8* buffer,u32 selection);
|
||||
extern int LoadFile(u8* buffer,u32 selection, char *filename);
|
||||
|
||||
#endif
|
||||
|
@ -92,9 +92,8 @@ int IsZipFile (char *buffer)
|
||||
/*****************************************************************************
|
||||
* UnZipBuffer
|
||||
*
|
||||
* It should be noted that there is a limit of 5MB total size for any ROM
|
||||
******************************************************************************/
|
||||
int UnZipBuffer (unsigned char *outbuffer, FILE *fd)
|
||||
int UnZipBuffer (unsigned char *outbuffer, FILE *fd, char *filename)
|
||||
{
|
||||
PKZIPHEADER pkzip;
|
||||
int zipoffset = 0;
|
||||
@ -137,21 +136,27 @@ int UnZipBuffer (unsigned char *outbuffer, FILE *fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** Get file name (first file) ***/
|
||||
int size = FLIP16 (pkzip.filenameLength);
|
||||
if (size > 255) size = 255;
|
||||
strncpy(filename, &readbuffer[sizeof(PKZIPHEADER)], size);
|
||||
filename[size] = 0;
|
||||
|
||||
/*** Set ZipChunk for first pass ***/
|
||||
zipoffset = (sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) + FLIP16 (pkzip.extraDataLength));
|
||||
zipoffset = (sizeof (PKZIPHEADER) + size + FLIP16 (pkzip.extraDataLength));
|
||||
zipchunk = ZIPCHUNK - zipoffset;
|
||||
|
||||
/*** Now do it! ***/
|
||||
do
|
||||
{
|
||||
zs.avail_in = zipchunk;
|
||||
zs.next_in = (Bytef *) & readbuffer[zipoffset];
|
||||
zs.next_in = (Bytef *) &readbuffer[zipoffset];
|
||||
|
||||
/*** Now inflate until input buffer is exhausted ***/
|
||||
do
|
||||
{
|
||||
zs.avail_out = ZIPCHUNK;
|
||||
zs.next_out = (Bytef *) & out;
|
||||
zs.next_out = (Bytef *) &out;
|
||||
res = inflate (&zs, Z_NO_FLUSH);
|
||||
|
||||
if (res == Z_MEM_ERROR)
|
||||
|
@ -30,6 +30,6 @@
|
||||
#define _UNZIP_H_
|
||||
|
||||
extern int IsZipFile (char *buffer);
|
||||
int UnZipBuffer (unsigned char *outbuffer, FILE *fd);
|
||||
int UnZipBuffer (unsigned char *outbuffer, FILE *fd, char *filename);
|
||||
|
||||
#endif
|
||||
|
@ -542,7 +542,7 @@ int FileSelector(void)
|
||||
areplay_shutdown();
|
||||
|
||||
/* load ROM file from device */
|
||||
size = LoadFile(cart.rom, selection);
|
||||
size = LoadFile(cart.rom, selection, fname);
|
||||
|
||||
/* exit menu */
|
||||
GUI_DeleteMenu(m);
|
||||
@ -557,7 +557,7 @@ int FileSelector(void)
|
||||
}
|
||||
|
||||
/* reinitialize emulation */
|
||||
reloadrom(size,filelist[selection].filename);
|
||||
reloadrom(size,fname);
|
||||
}
|
||||
|
||||
return size;
|
||||
|
@ -32,6 +32,10 @@
|
||||
|
||||
#include <ogc/lwp_threads.h>
|
||||
|
||||
#ifdef HW_RVL
|
||||
#include <ogc/usbmouse.h>
|
||||
#endif
|
||||
|
||||
/* Credits */
|
||||
extern const u8 Bg_credits_png[];
|
||||
|
||||
@ -77,10 +81,16 @@ extern const u8 Button_delete_over_png[];
|
||||
|
||||
/* Controller Settings */
|
||||
extern const u8 Ctrl_4wayplay_png[];
|
||||
extern const u8 Ctrl_gamepad_png[];
|
||||
extern const u8 Ctrl_gamepad_md_png[];
|
||||
extern const u8 Ctrl_gamepad_ms_png[];
|
||||
extern const u8 Ctrl_justifiers_png[];
|
||||
extern const u8 Ctrl_menacer_png[];
|
||||
extern const u8 Ctrl_mouse_png[];
|
||||
extern const u8 Ctrl_xe_a1p_png[];
|
||||
extern const u8 Ctrl_activator_png[];
|
||||
extern const u8 Ctrl_lightphaser_png[];
|
||||
extern const u8 Ctrl_paddle_png[];
|
||||
extern const u8 Ctrl_sportspad_png[];
|
||||
extern const u8 Ctrl_none_png[];
|
||||
extern const u8 Ctrl_teamplayer_png[];
|
||||
extern const u8 Ctrl_pad3b_png[];
|
||||
@ -1011,6 +1021,15 @@ static void soundmenu ()
|
||||
* System Settings menu
|
||||
*
|
||||
****************************************************************************/
|
||||
static const uint16 vc_table[4][2] =
|
||||
{
|
||||
/* NTSC, PAL */
|
||||
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||
{0xEA , 0x102}, /* Mode 5 (224 lines) */
|
||||
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||
{0x106, 0x10A} /* Mode 5 (240 lines) */
|
||||
};
|
||||
|
||||
static void systemmenu ()
|
||||
{
|
||||
int ret, quit = 0;
|
||||
@ -1104,11 +1123,7 @@ static void systemmenu ()
|
||||
}
|
||||
|
||||
/* reinitialize VC max value */
|
||||
vc_max = 0xEA + 24*vdp_pal;
|
||||
if (reg[1] & 8)
|
||||
{
|
||||
vc_max += (28 - 20*vdp_pal);
|
||||
}
|
||||
vc_max = vc_table[(reg[1] >> 2) & 3][vdp_pal];
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1119,7 +1134,10 @@ static void systemmenu ()
|
||||
|
||||
case 2: /*** 68k Address Error ***/
|
||||
config.addr_error ^= 1;
|
||||
cart_hw_init ();
|
||||
if (system_hw != SYSTEM_PBC)
|
||||
{
|
||||
md_cart_init ();
|
||||
}
|
||||
sprintf (items[2].text, "68k Address Error: %s", config.addr_error ? "ON" : "OFF");
|
||||
break;
|
||||
|
||||
@ -1449,6 +1467,9 @@ static void videomenu ()
|
||||
sprintf (items[VI_OFFSET+1].text, "Borders: V ONLY");
|
||||
else
|
||||
sprintf (items[VI_OFFSET+1].text, "Borders: NONE");
|
||||
|
||||
/* update viewport */
|
||||
bitmap.viewport.x = (config.overscan & 2) * 7;
|
||||
break;
|
||||
|
||||
case VI_OFFSET+2: /*** aspect ratio ***/
|
||||
@ -1614,7 +1635,7 @@ static void ctrlmenu_raz(void)
|
||||
{
|
||||
m->buttons[i+2].data = &button_player_data;
|
||||
m->buttons[i+2].state |= BUTTON_ACTIVE;
|
||||
if (cart.jcart && (i > 4))
|
||||
if ((cart.special & HW_J_CART) && (i > 4))
|
||||
sprintf(m->items[i+2].comment,"Configure Player %d (J-CART) settings", max + 1);
|
||||
else
|
||||
sprintf(m->items[i+2].comment,"Configure Player %d settings", max + 1);
|
||||
@ -1696,47 +1717,65 @@ static void ctrlmenu(void)
|
||||
gui_item *items = NULL;
|
||||
u8 *special = NULL;
|
||||
u32 exp;
|
||||
u8 type = 0;
|
||||
|
||||
/* System devices */
|
||||
gui_item items_sys[2][7] =
|
||||
gui_item items_sys[2][13] =
|
||||
{
|
||||
{
|
||||
{NULL,Ctrl_none_png ,"","Select Port 1 device",110,130,48,72},
|
||||
{NULL,Ctrl_gamepad_png ,"","Select Port 1 device", 87,117,96,84},
|
||||
{NULL,Ctrl_gamepad_md_png ,"","Select Port 1 device", 85,117,96,84},
|
||||
{NULL,Ctrl_mouse_png ,"","Select Port 1 device", 97,113,64,88},
|
||||
{NULL,Ctrl_menacer_png ,"","Select Port 1 device", 94,113,80,88},
|
||||
{NULL,Ctrl_justifiers_png ,"","Select Port 1 device", 88,117,80,84},
|
||||
{NULL,Ctrl_xe_a1p_png ,"","Select Port 1 device", 98,118,72,84},
|
||||
{NULL,Ctrl_activator_png ,"","Select Port 1 device", 94,121,72,80},
|
||||
{NULL,Ctrl_gamepad_ms_png ,"","Select Port 1 device", 91,125,84,76},
|
||||
{NULL,Ctrl_lightphaser_png,"","Select Port 1 device", 89,109,88,92},
|
||||
{NULL,Ctrl_paddle_png ,"","Select Port 1 device", 86,117,96,84},
|
||||
{NULL,Ctrl_sportspad_png ,"","Select Port 1 device", 95,117,76,84},
|
||||
{NULL,Ctrl_teamplayer_png ,"","Select Port 1 device", 94,109,80,92},
|
||||
{NULL,Ctrl_4wayplay_png ,"","Select Port 1 device", 98,110,72,92}
|
||||
},
|
||||
{
|
||||
{NULL,Ctrl_none_png ,"","Select Port 2 device",110,300,48,72},
|
||||
{NULL,Ctrl_gamepad_png ,"","Select Port 2 device", 87,287,96,84},
|
||||
{NULL,Ctrl_gamepad_md_png ,"","Select Port 2 device", 85,287,96,84},
|
||||
{NULL,Ctrl_mouse_png ,"","Select Port 2 device", 97,283,64,88},
|
||||
{NULL,Ctrl_menacer_png ,"","Select Port 2 device", 94,283,80,88},
|
||||
{NULL,Ctrl_justifiers_png ,"","Select Port 2 device", 88,287,80,84},
|
||||
{NULL,Ctrl_xe_a1p_png ,"","Select Port 2 device", 98,288,72,84},
|
||||
{NULL,Ctrl_activator_png ,"","Select Port 2 device", 94,291,72,80},
|
||||
{NULL,Ctrl_gamepad_ms_png ,"","Select Port 2 device", 91,295,84,76},
|
||||
{NULL,Ctrl_lightphaser_png,"","Select Port 2 device", 89,279,88,92},
|
||||
{NULL,Ctrl_paddle_png ,"","Select Port 2 device", 86,287,96,84},
|
||||
{NULL,Ctrl_sportspad_png ,"","Select Port 2 device", 95,287,76,84},
|
||||
{NULL,Ctrl_teamplayer_png ,"","Select Port 2 device", 94,279,80,92},
|
||||
{NULL,Ctrl_4wayplay_png ,"","Select Port 2 device", 98,280,72,92}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/* Player Configuration special items */
|
||||
gui_item items_special[3][2] =
|
||||
/* Specific controller options */
|
||||
gui_item items_special[4][2] =
|
||||
{
|
||||
{
|
||||
/* Gamepad options */
|
||||
/* Gamepad option */
|
||||
{NULL,Ctrl_pad3b_png,"Pad\nType","Use 3-buttons Pad",528,180,44,28},
|
||||
{NULL,Ctrl_pad6b_png,"Pad\nType","Use 6-buttons Pad",528,180,44,28}
|
||||
},
|
||||
{
|
||||
/* Mouse options */
|
||||
{NULL,ctrl_option_off_png,"Invert\nMouse","Enable/Disable Mouse Y-Axis inversion",534,180,24,24},
|
||||
{NULL,ctrl_option_on_png ,"Invert\nMouse","Enable/Disable Mouse Y-Axis inversion",534,180,24,24},
|
||||
/* Mouse option */
|
||||
{NULL,ctrl_option_off_png,"Invert\nMouse","Enable/Disable Y-Axis inversion",534,180,24,24},
|
||||
{NULL,ctrl_option_on_png ,"Invert\nMouse","Enable/Disable Y-Axis inversion",534,180,24,24},
|
||||
},
|
||||
{
|
||||
/* Gun options */
|
||||
/* Gun option */
|
||||
{NULL,ctrl_option_off_png,"Show\nCursor","Enable/Disable Lightgun cursor",534,180,24,24},
|
||||
{NULL,ctrl_option_on_png ,"Show\nCursor","Enable/Disable Lightgun cursor",534,180,24,24},
|
||||
},
|
||||
{
|
||||
/* no option */
|
||||
{NULL,NULL,"No Option","",436,180,160,52},
|
||||
{NULL,NULL,"","",0,0,0,0},
|
||||
}
|
||||
};
|
||||
|
||||
@ -1768,13 +1807,10 @@ static void ctrlmenu(void)
|
||||
button_player_none_data.texture[0] = gxTextureOpenPNG(button_player_none_data.image[0],0);
|
||||
|
||||
/* initialize custom images */
|
||||
items_sys[1][0].texture = items_sys[0][0].texture = gxTextureOpenPNG(items_sys[0][0].data,0);
|
||||
items_sys[1][1].texture = items_sys[0][1].texture = gxTextureOpenPNG(items_sys[0][1].data,0);
|
||||
items_sys[1][2].texture = items_sys[0][2].texture = gxTextureOpenPNG(items_sys[0][2].data,0);
|
||||
items_sys[1][3].texture = items_sys[0][3].texture = gxTextureOpenPNG(items_sys[0][3].data,0);
|
||||
items_sys[1][4].texture = items_sys[0][4].texture = gxTextureOpenPNG(items_sys[0][4].data,0);
|
||||
items_sys[1][5].texture = items_sys[0][5].texture = gxTextureOpenPNG(items_sys[0][5].data,0);
|
||||
items_sys[1][6].texture = items_sys[0][6].texture = gxTextureOpenPNG(items_sys[0][6].data,0);
|
||||
for (i=0; i<13; i++)
|
||||
{
|
||||
items_sys[1][i].texture = items_sys[0][i].texture = gxTextureOpenPNG(items_sys[0][i].data,0);
|
||||
}
|
||||
items_special[0][0].texture = gxTextureOpenPNG(items_special[0][0].data,0);
|
||||
items_special[0][1].texture = gxTextureOpenPNG(items_special[0][1].data,0);
|
||||
items_special[2][0].texture = items_special[1][0].texture = gxTextureOpenPNG(items_special[1][0].data,0);
|
||||
@ -1811,16 +1847,8 @@ static void ctrlmenu(void)
|
||||
{
|
||||
case 0: /* update port 1 system */
|
||||
{
|
||||
if (input.system[0] == SYSTEM_MOUSE)
|
||||
{
|
||||
/* lightguns are never used on Port 1 */
|
||||
input.system[0] += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* next connected device */
|
||||
input.system[0]++;
|
||||
}
|
||||
/* next connected device */
|
||||
input.system[0]++;
|
||||
|
||||
/* allow only one connected mouse */
|
||||
if ((input.system[0] == SYSTEM_MOUSE) && (input.system[1] == SYSTEM_MOUSE))
|
||||
@ -1828,6 +1856,18 @@ static void ctrlmenu(void)
|
||||
input.system[0] += 3;
|
||||
}
|
||||
|
||||
/* Menacer & Justifiers on Port B only */
|
||||
if (input.system[0] == SYSTEM_MENACER)
|
||||
{
|
||||
input.system[0] += 2;
|
||||
}
|
||||
|
||||
/* allow only one gun type */
|
||||
if ((input.system[0] == SYSTEM_LIGHTPHASER) && ((input.system[1] == SYSTEM_MENACER) || (input.system[1] == SYSTEM_JUSTIFIER)))
|
||||
{
|
||||
input.system[0] ++;
|
||||
}
|
||||
|
||||
/* 4-wayplay uses both ports */
|
||||
if (input.system[0] == SYSTEM_WAYPLAY)
|
||||
{
|
||||
@ -1838,7 +1878,7 @@ static void ctrlmenu(void)
|
||||
if (input.system[0] > SYSTEM_WAYPLAY)
|
||||
{
|
||||
input.system[0] = NO_SYSTEM;
|
||||
input.system[1] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_MD_GAMEPAD;
|
||||
}
|
||||
|
||||
/* reset I/O ports */
|
||||
@ -1886,7 +1926,7 @@ static void ctrlmenu(void)
|
||||
case 1: /* update port 2 system */
|
||||
{
|
||||
/* J-CART uses fixed configuration */
|
||||
if (cart.jcart) break;
|
||||
if (cart.special & HW_J_CART) break;
|
||||
|
||||
/* next connected device */
|
||||
input.system[1] ++;
|
||||
@ -1897,6 +1937,24 @@ static void ctrlmenu(void)
|
||||
input.system[1] ++;
|
||||
}
|
||||
|
||||
/* allow only one gun type */
|
||||
if ((input.system[0] == SYSTEM_LIGHTPHASER) && (input.system[1] == SYSTEM_MENACER))
|
||||
{
|
||||
input.system[1] += 3;
|
||||
}
|
||||
|
||||
/* allow only one gun type */
|
||||
if ((input.system[0] == SYSTEM_LIGHTPHASER) && (input.system[1] == SYSTEM_JUSTIFIER))
|
||||
{
|
||||
input.system[1] += 2;
|
||||
}
|
||||
|
||||
/* XE-1AP on port A only */
|
||||
if (input.system[1] == SYSTEM_XE_A1P)
|
||||
{
|
||||
input.system[1] ++;
|
||||
}
|
||||
|
||||
/* 4-wayplay uses both ports */
|
||||
if (input.system[1] == SYSTEM_WAYPLAY)
|
||||
{
|
||||
@ -1907,7 +1965,7 @@ static void ctrlmenu(void)
|
||||
if (input.system[1] > SYSTEM_WAYPLAY)
|
||||
{
|
||||
input.system[1] = NO_SYSTEM;
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[0] = SYSTEM_MD_GAMEPAD;
|
||||
}
|
||||
|
||||
/* reset I/O ports */
|
||||
@ -2010,24 +2068,61 @@ static void ctrlmenu(void)
|
||||
m->buttons[9].shift[3] = 1;
|
||||
}
|
||||
|
||||
/* emulated device type */
|
||||
type = input.dev[m->selected - 2];
|
||||
|
||||
/* retrieve current player informations */
|
||||
if (input.dev[m->selected-2] == DEVICE_LIGHTGUN)
|
||||
switch (type)
|
||||
{
|
||||
items = items_special[2];
|
||||
special = &config.gun_cursor[m->selected & 1];
|
||||
case DEVICE_PAD3B:
|
||||
case DEVICE_PAD6B:
|
||||
{
|
||||
items = items_special[0];
|
||||
special = &config.input[player].padtype;
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_MOUSE:
|
||||
{
|
||||
items = items_special[1];
|
||||
special = &config.invert_mouse;
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_LIGHTGUN:
|
||||
{
|
||||
items = items_special[2];
|
||||
|
||||
if ((input.system[1] == SYSTEM_MENACER) || (input.system[1] == SYSTEM_JUSTIFIER))
|
||||
{
|
||||
/* Menacer & Justifiers affected to devices 4 & 5 */
|
||||
special = &config.gun_cursor[m->selected & 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lightphasers affected to devices 0 & 4 */
|
||||
special = &config.gun_cursor[m->selected >> 2];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
items = items_special[3];
|
||||
special = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (input.dev[m->selected-2] == DEVICE_MOUSE)
|
||||
|
||||
if (special)
|
||||
{
|
||||
items = items_special[1];
|
||||
special = &config.invert_mouse;
|
||||
memcpy(&m->items[10],&items[*special],sizeof(gui_item));
|
||||
}
|
||||
else
|
||||
{
|
||||
items = items_special[0];
|
||||
special = &config.input[player].padtype;
|
||||
memcpy(&m->items[10],&items[0],sizeof(gui_item));
|
||||
}
|
||||
|
||||
memcpy(&m->items[10],&items[*special],sizeof(gui_item));
|
||||
memcpy(&m->items[11],&items_device[config.input[player].device + 1],sizeof(gui_item));
|
||||
|
||||
/* slide in configuration window */
|
||||
@ -2037,8 +2132,18 @@ static void ctrlmenu(void)
|
||||
m->selected = 10;
|
||||
GUI_DrawMenuFX(m, 20, 0);
|
||||
|
||||
/* some devices require analog sticks */
|
||||
if ((type == DEVICE_XE_A1P) && ((config.input[player].device == -1) || (config.input[player].device == 1)))
|
||||
{
|
||||
GUI_WaitPrompt("Warning","One Analog Stick required !");
|
||||
}
|
||||
else if ((type == DEVICE_ACTIVATOR) && ((config.input[player].device != 0) && (config.input[player].device != 3)))
|
||||
{
|
||||
GUI_WaitPrompt("Warning","Two Analog Sticks required !");
|
||||
}
|
||||
|
||||
/* update title */
|
||||
if (cart.jcart && (player > 1))
|
||||
if ((cart.special & HW_J_CART) && (player > 1))
|
||||
{
|
||||
sprintf(m->title,"Controller Settings (Player %d) (J-CART)",player+1);
|
||||
}
|
||||
@ -2051,20 +2156,25 @@ static void ctrlmenu(void)
|
||||
|
||||
case 10: /* specific option */
|
||||
{
|
||||
if (special == &config.input[player].padtype)
|
||||
{
|
||||
if (config.input[player].device == 1) break;
|
||||
config.input[player].padtype ^= 1;
|
||||
input_init();
|
||||
input_reset();
|
||||
}
|
||||
else
|
||||
if (special)
|
||||
{
|
||||
/* switch option */
|
||||
*special ^= 1;
|
||||
}
|
||||
|
||||
/* update menu items */
|
||||
memcpy(&m->items[10],&items[*special],sizeof(gui_item));
|
||||
/* specific case: controller type */
|
||||
if (type < 2)
|
||||
{
|
||||
/* re-initialize emulated device */
|
||||
input_init();
|
||||
input_reset();
|
||||
|
||||
/* update emulated device type */
|
||||
type = *special;
|
||||
}
|
||||
|
||||
/* update menu items */
|
||||
memcpy(&m->items[10],&items[*special],sizeof(gui_item));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2205,8 +2315,11 @@ static void ctrlmenu(void)
|
||||
/* force 3-buttons gamepad when using Wiimote */
|
||||
if (config.input[player].device == 1)
|
||||
{
|
||||
config.input[player].padtype = DEVICE_3BUTTON;
|
||||
memcpy(&m->items[10],&items[*special],sizeof(gui_item));
|
||||
config.input[player].padtype = DEVICE_PAD3B;
|
||||
if (special)
|
||||
{
|
||||
memcpy(&m->items[10],&items[*special],sizeof(gui_item));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2218,30 +2331,12 @@ static void ctrlmenu(void)
|
||||
|
||||
case 12: /* Controller Keys Configuration */
|
||||
{
|
||||
if (config.input[player].device < 0) break;
|
||||
|
||||
GUI_MsgBoxOpen("Keys Configuration", "",0);
|
||||
|
||||
if (config.input[player].padtype == DEVICE_6BUTTON)
|
||||
if (config.input[player].device >= 0)
|
||||
{
|
||||
/* 6-buttons gamepad */
|
||||
if (config.input[player].device == 0)
|
||||
{
|
||||
/* Gamecube PAD: 6-buttons w/o MODE */
|
||||
gx_input_Config(config.input[player].port, config.input[player].device, 7);
|
||||
}
|
||||
else
|
||||
{
|
||||
gx_input_Config(config.input[player].port, config.input[player].device, 8);
|
||||
}
|
||||
GUI_MsgBoxOpen("Keys Configuration", "",0);
|
||||
gx_input_Config(config.input[player].port, config.input[player].device, type);
|
||||
GUI_MsgBoxClose();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 3-Buttons gamepad, mouse, lightgun */
|
||||
gx_input_Config(config.input[player].port, config.input[player].device, 4);
|
||||
}
|
||||
|
||||
GUI_MsgBoxClose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2364,13 +2459,10 @@ static void ctrlmenu(void)
|
||||
gxTextureClose(&button_player_none_data.texture[0]);
|
||||
|
||||
/* delete custom images */
|
||||
gxTextureClose(&items_sys[0][0].texture);
|
||||
gxTextureClose(&items_sys[0][1].texture);
|
||||
gxTextureClose(&items_sys[0][2].texture);
|
||||
gxTextureClose(&items_sys[0][3].texture);
|
||||
gxTextureClose(&items_sys[0][4].texture);
|
||||
gxTextureClose(&items_sys[0][5].texture);
|
||||
gxTextureClose(&items_sys[0][6].texture);
|
||||
for (i=0; i<13; i++)
|
||||
{
|
||||
gxTextureClose(&items_sys[0][i].texture);
|
||||
}
|
||||
gxTextureClose(&items_special[0][0].texture);
|
||||
gxTextureClose(&items_special[0][1].texture);
|
||||
gxTextureClose(&items_special[1][0].texture);
|
||||
@ -3284,6 +3376,16 @@ void menu_execute(void)
|
||||
#ifdef HW_RVL
|
||||
while (WPAD_ButtonsHeld(0)) WPAD_ScanPads();
|
||||
gxTextureClose(&w_pointer);
|
||||
|
||||
/* USB Mouse support */
|
||||
if ((input.system[0] == SYSTEM_MOUSE) || (input.system[1] == SYSTEM_MOUSE))
|
||||
{
|
||||
MOUSE_Init();
|
||||
}
|
||||
else
|
||||
{
|
||||
MOUSE_Deinit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
1054
source/gx/gx_input.c
@ -31,7 +31,7 @@
|
||||
#define MAX_INPUTS 8
|
||||
#endif
|
||||
|
||||
/* Genesis controller keys */
|
||||
/* Configurable keys */
|
||||
#define MAX_KEYS 8
|
||||
|
||||
/* Key configuration structure */
|
||||
@ -46,7 +46,7 @@ typedef struct
|
||||
extern void gx_input_Init(void);
|
||||
extern int gx_input_FindDevices(void);
|
||||
extern void gx_input_SetDefault(void);
|
||||
extern void gx_input_Config(u8 num, u8 type, u8 max_keys);
|
||||
extern void gx_input_Config(u8 chan, u8 device, u8 type);
|
||||
extern void gx_input_UpdateEmu(void);
|
||||
extern void gx_input_UpdateMenu(u32 cnt);
|
||||
|
||||
|
@ -477,7 +477,7 @@ static void gxSetAspectRatio(int *xscale, int *yscale)
|
||||
if (config.overscan & 2)
|
||||
{
|
||||
/* max visible range is ~712 pixels, not 720 */
|
||||
*xscale = 356;
|
||||
*xscale = (reg[12] & 1) ? 356 : 360;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1400,11 +1400,11 @@ void gx_video_Start(void)
|
||||
}
|
||||
|
||||
/* lightgun textures */
|
||||
if (config.gun_cursor[0] && (input.dev[4] == DEVICE_LIGHTGUN))
|
||||
if (config.gun_cursor[0] && ((input.system[1] == SYSTEM_MENACER) || (input.system[1] == SYSTEM_JUSTIFIER) || (input.system[0] == SYSTEM_LIGHTPHASER)))
|
||||
{
|
||||
crosshair[0] = gxTextureOpenPNG(Crosshair_p1_png,0);
|
||||
}
|
||||
if (config.gun_cursor[1] && (input.dev[5] == DEVICE_LIGHTGUN))
|
||||
if (config.gun_cursor[1] && ((input.system[1] == SYSTEM_JUSTIFIER) || (input.system[1] == SYSTEM_LIGHTPHASER)))
|
||||
{
|
||||
crosshair[1] = gxTextureOpenPNG(Crosshair_p2_png,0);
|
||||
}
|
||||
@ -1486,14 +1486,30 @@ void gx_video_Update(void)
|
||||
/* render textured quad */
|
||||
draw_square();
|
||||
|
||||
/* Lightgun marks */
|
||||
/* Lightgun # 1 screen mark */
|
||||
if (crosshair[0])
|
||||
{
|
||||
gxDrawCrosshair(crosshair[0], input.analog[0][0],input.analog[0][1]);
|
||||
if (input.system[0] == SYSTEM_LIGHTPHASER)
|
||||
{
|
||||
gxDrawCrosshair(crosshair[0], input.analog[0][0],input.analog[0][1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gxDrawCrosshair(crosshair[0], input.analog[4][0],input.analog[4][1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Lightgun # 2 screen mark */
|
||||
if (crosshair[1])
|
||||
{
|
||||
gxDrawCrosshair(crosshair[1], input.analog[1][0],input.analog[1][1]);
|
||||
if (input.system[1] == SYSTEM_LIGHTPHASER)
|
||||
{
|
||||
gxDrawCrosshair(crosshair[1], input.analog[1][0],input.analog[1][1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gxDrawCrosshair(crosshair[1], input.analog[5][0],input.analog[5][1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* swap XFB */
|
||||
|
BIN
source/gx/images/Ctrl_activator.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
source/gx/images/Ctrl_gamepad_md.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
source/gx/images/Ctrl_gamepad_ms.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
source/gx/images/Ctrl_lightphaser.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
source/gx/images/Ctrl_paddle.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
source/gx/images/Ctrl_sportspad.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
source/gx/images/Ctrl_xe_a1p.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
@ -4,7 +4,7 @@
|
||||
* Genesis Plus GX
|
||||
*
|
||||
* Softdev (2006)
|
||||
* Eke-Eke (2007,2008,2009)
|
||||
* Eke-Eke (2007-2010)
|
||||
*
|
||||
* 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
|
||||
@ -53,13 +53,21 @@ u32 ConfigRequested = 1;
|
||||
/****************************************************************************
|
||||
* Power Button callback
|
||||
***************************************************************************/
|
||||
static void Power_Off(void)
|
||||
static void PowerOff_cb(void)
|
||||
{
|
||||
Shutdown = 1;
|
||||
ConfigRequested = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Reset Button callback
|
||||
***************************************************************************/
|
||||
static void Reset_cb(void)
|
||||
{
|
||||
gen_reset(0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Genesis Plus Virtual Machine
|
||||
*
|
||||
@ -202,24 +210,43 @@ void reloadrom (int size, char *name)
|
||||
/* hot-swap previous & current cartridge */
|
||||
bool hotswap = config.hot_swap && cart.romsize;
|
||||
|
||||
/* load ROM file */
|
||||
/* ROM size */
|
||||
cart.romsize = size;
|
||||
|
||||
/* load ROM file */
|
||||
load_rom(name);
|
||||
|
||||
/* ROM filename without extension*/
|
||||
sprintf(rom_filename,"%s",name);
|
||||
rom_filename[strlen(rom_filename) - 4] = 0;
|
||||
|
||||
if (hotswap)
|
||||
{
|
||||
cart_hw_init();
|
||||
cart_hw_reset(1);
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
sms_cart_init();
|
||||
sms_cart_reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
md_cart_init();
|
||||
md_cart_reset(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* initialize audio back-end */
|
||||
/* 60hz video mode requires synchronization with Video Interrupt. */
|
||||
/* Framerate is 59.94 fps in interlaced/progressive modes, ~59.825 fps in non-interlaced mode */
|
||||
/* initialize audio emulation */
|
||||
|
||||
/* To prevent any sound skipping, sound chips must run at the exact same speed as the rest of emulation (see sound.c) */
|
||||
/* In 60hz video modes with NTSC emulation, we need perfect synchronization with video hardware interrupt (VSYNC) */
|
||||
/* Wii & GC framerate has been measured to be exactly 59.94 fps in 240i/480i/480p video modes, ~59.825 fps in 240p */
|
||||
/* In other modes, emulation is synchronized with audio hardware instead and we use default framerates (50Hz for PAL, 60Hz for NTSC). */
|
||||
float framerate = vdp_pal ? 50.0 : ((config.tv_mode == 1) ? 60.0 : (config.render ? 59.94 : (1000000.0/16715.0)));
|
||||
|
||||
/* output samplerate has been measured to be ~48044 samples/sec on GC, 48000 samples/sec on Wii */
|
||||
audio_init(SAMPLERATE_48KHZ, framerate);
|
||||
|
||||
/* System Power ON */
|
||||
/* system power ON */
|
||||
system_init ();
|
||||
system_reset ();
|
||||
}
|
||||
@ -273,6 +300,8 @@ u32 frameticker = 0;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
char pathname[MAXPATHLEN];
|
||||
|
||||
#ifdef HW_RVL
|
||||
/* initialize DI interface */
|
||||
DI_UseCache(0);
|
||||
@ -305,7 +334,6 @@ int main (int argc, char *argv[])
|
||||
if (fatMounted)
|
||||
{
|
||||
/* base directory */
|
||||
char pathname[MAXPATHLEN];
|
||||
sprintf (pathname, DEFAULT_PATH);
|
||||
DIR_ITER *dir = diropen(pathname);
|
||||
if (dir) dirclose(dir);
|
||||
@ -356,10 +384,10 @@ int main (int argc, char *argv[])
|
||||
SILENT = 1;
|
||||
if (OpenDirectory(TYPE_RECENT))
|
||||
{
|
||||
int size = LoadFile(cart.rom,0);
|
||||
int size = LoadFile(cart.rom,0,pathname);
|
||||
if (size)
|
||||
{
|
||||
reloadrom(size,filelist[0].filename);
|
||||
reloadrom(size,pathname);
|
||||
gx_video_Start();
|
||||
gx_audio_Start();
|
||||
frameticker = 1;
|
||||
@ -371,9 +399,12 @@ int main (int argc, char *argv[])
|
||||
|
||||
#ifdef HW_RVL
|
||||
/* power button callback */
|
||||
SYS_SetPowerCallback(Power_Off);
|
||||
SYS_SetPowerCallback(PowerOff_cb);
|
||||
#endif
|
||||
|
||||
/* reset button callback */
|
||||
SYS_SetResetCallback(Reset_cb);
|
||||
|
||||
/* main emulation loop */
|
||||
run_emulation();
|
||||
|
||||
|
@ -2,8 +2,6 @@
|
||||
#ifndef _OSD_H_
|
||||
#define _OSD_H_
|
||||
|
||||
#define NGC 1
|
||||
|
||||
#include <gccore.h>
|
||||
#include <ogcsys.h>
|
||||
#include <stdio.h>
|
||||
@ -33,9 +31,9 @@
|
||||
#define SK_UPMEM "/genplus/sk2chip.bin"
|
||||
|
||||
#ifdef HW_RVL
|
||||
#define VERSION "Genesis Plus GX 1.4.1 (WII)"
|
||||
#define VERSION "Genesis Plus GX 1.5.0 (WII)"
|
||||
#else
|
||||
#define VERSION "Genesis Plus GX 1.4.1 (GCN)"
|
||||
#define VERSION "Genesis Plus GX 1.5.0 (GCN)"
|
||||
#endif
|
||||
|
||||
#define osd_input_Update() gx_input_UpdateEmu()
|
||||
|
923
source/hvc.h
@ -125,7 +125,7 @@
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* H-counter timings in H40 & H32 modes (starts from HINT) */
|
||||
/* H-counter timings in H32 & H40 modes (starts from HINT) */
|
||||
/* */
|
||||
/* There are exactly 3420 Master Clock counts per raster line. */
|
||||
/* */
|
||||
@ -138,483 +138,480 @@
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
static const uint8 cycle2hc40[3420] =
|
||||
{
|
||||
/* end of active display (16 pixels -> 128 Mcycles) , HINT triggered , Vcounter increment */
|
||||
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
|
||||
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
|
||||
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
|
||||
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
|
||||
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
|
||||
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
|
||||
|
||||
/* right border (14 pixels -> 112 Mcycles) */
|
||||
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
|
||||
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
|
||||
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
|
||||
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
|
||||
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
|
||||
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
|
||||
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
|
||||
|
||||
/* right blanking (9 pixels -> 72 Mcycles) , VDP status HBLANK flag set */
|
||||
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
|
||||
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
|
||||
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4,
|
||||
0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
|
||||
0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
|
||||
|
||||
/* horizontal sync (32 pixels -> 313 Mcycles) */
|
||||
0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
|
||||
0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
|
||||
0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8,
|
||||
0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9,
|
||||
0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea,
|
||||
0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb,
|
||||
0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
|
||||
0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec,
|
||||
0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
|
||||
0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee,
|
||||
0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef,
|
||||
0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
|
||||
0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
|
||||
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3,
|
||||
0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4,
|
||||
0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
|
||||
0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
|
||||
0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6,
|
||||
0xf6,
|
||||
|
||||
/* left blanking (32 pixels -> 259 Mcycles) */
|
||||
0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
|
||||
0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8,
|
||||
0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9,
|
||||
0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa,
|
||||
0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb,
|
||||
0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc,
|
||||
0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd,
|
||||
0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe,
|
||||
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
/* Vertical Interrupt triggered */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06,
|
||||
|
||||
/* left border (13 pixels -> 104 Mcycles) , VDP status HBLANK flag cleared */
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a,
|
||||
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
|
||||
/* remaining active display (304 pixels -> 2432 Mcycles) */
|
||||
0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e,
|
||||
0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12,
|
||||
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
|
||||
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
|
||||
0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16,
|
||||
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
|
||||
0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
|
||||
0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a,
|
||||
0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b,
|
||||
0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c,
|
||||
0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d,
|
||||
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e,
|
||||
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f,
|
||||
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21,
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23,
|
||||
0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25,
|
||||
0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26,
|
||||
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27,
|
||||
0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28,
|
||||
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29,
|
||||
0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a,
|
||||
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b,
|
||||
0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c,
|
||||
0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e,
|
||||
0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f,
|
||||
0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
|
||||
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32,
|
||||
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33,
|
||||
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34,
|
||||
0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35,
|
||||
0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37,
|
||||
0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38,
|
||||
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39,
|
||||
0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a,
|
||||
0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b,
|
||||
0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c,
|
||||
0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d,
|
||||
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43,
|
||||
0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45,
|
||||
0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x46,
|
||||
0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47,
|
||||
0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48,
|
||||
0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49,
|
||||
0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a,
|
||||
0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b,
|
||||
0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c,
|
||||
0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d,
|
||||
0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e,
|
||||
0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f,
|
||||
0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51,
|
||||
0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52,
|
||||
0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53,
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54,
|
||||
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56,
|
||||
0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57,
|
||||
0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58,
|
||||
0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59,
|
||||
0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5a,
|
||||
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b,
|
||||
0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c,
|
||||
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d,
|
||||
0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e,
|
||||
0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f,
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61,
|
||||
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62,
|
||||
0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63,
|
||||
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64,
|
||||
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65,
|
||||
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67,
|
||||
0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68,
|
||||
0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69,
|
||||
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a,
|
||||
0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b,
|
||||
0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c,
|
||||
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d,
|
||||
0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e,
|
||||
0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f,
|
||||
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x70,
|
||||
0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71,
|
||||
0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72,
|
||||
0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73,
|
||||
0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74,
|
||||
0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75,
|
||||
0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76,
|
||||
0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77,
|
||||
0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78,
|
||||
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79,
|
||||
0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a,
|
||||
0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b,
|
||||
0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c,
|
||||
0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d,
|
||||
0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e,
|
||||
0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f,
|
||||
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80,
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81,
|
||||
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
|
||||
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84,
|
||||
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85,
|
||||
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x86,
|
||||
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87,
|
||||
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x88,
|
||||
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89,
|
||||
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a,
|
||||
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b,
|
||||
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8c,
|
||||
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8d,
|
||||
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e,
|
||||
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f,
|
||||
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90,
|
||||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91,
|
||||
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92,
|
||||
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93,
|
||||
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94,
|
||||
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x95,
|
||||
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x96, 0x96, 0x96, 0x96,
|
||||
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97,
|
||||
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, 0x98,
|
||||
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9a,
|
||||
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9c,
|
||||
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d,
|
||||
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e,
|
||||
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, 0x9f, 0x9f,
|
||||
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa0,
|
||||
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1,
|
||||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2,
|
||||
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3,
|
||||
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4,
|
||||
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
|
||||
};
|
||||
|
||||
static const uint8 cycle2hc32[3420] =
|
||||
{
|
||||
/* end of active display (16 pixels -> 160 Mcycles) , HINT triggered ? , Vcounter increment */
|
||||
0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
|
||||
0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
|
||||
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
|
||||
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x88,
|
||||
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
|
||||
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
|
||||
0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
|
||||
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
|
||||
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8c,
|
||||
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
|
||||
static const uint8 cycle2hc32[3420] =
|
||||
{
|
||||
/* end of active display (16 pixels -> 160 Mcycles) , H interrupt triggered, Vcounter increment */
|
||||
0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
|
||||
0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
|
||||
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
|
||||
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x88,
|
||||
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
|
||||
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
|
||||
0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
|
||||
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
|
||||
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8c,
|
||||
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
|
||||
|
||||
/* right border (14 pixels -> 140 Mcycles) */
|
||||
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
|
||||
0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
|
||||
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
|
||||
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90,
|
||||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||||
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
|
||||
0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
|
||||
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
|
||||
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
|
||||
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
|
||||
0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
|
||||
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
|
||||
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90,
|
||||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||||
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
|
||||
0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
|
||||
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
|
||||
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
|
||||
|
||||
/* right blanking (9 pixels -> 90 Mcycles) , VDP status HBLANK flag set */
|
||||
0xe9, 0xe9, 0xe9, 0xe9,
|
||||
0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9,
|
||||
0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea,
|
||||
0xea, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
|
||||
0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec,
|
||||
0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed,
|
||||
0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
|
||||
0xe9, 0xe9, 0xe9, 0xe9,
|
||||
0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9,
|
||||
0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea,
|
||||
0xea, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
|
||||
0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec,
|
||||
0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed,
|
||||
0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
|
||||
|
||||
/* horizontal sync (26 pixels -> 260 Mcycles) */
|
||||
0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
|
||||
0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
||||
0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
|
||||
0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1,
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
|
||||
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
|
||||
0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3,
|
||||
0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
|
||||
0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5,
|
||||
0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
|
||||
0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6,
|
||||
0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
|
||||
0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
|
||||
0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9,
|
||||
0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9,
|
||||
0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
|
||||
0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
|
||||
0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
||||
0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
|
||||
0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1,
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
|
||||
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
|
||||
0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3,
|
||||
0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
|
||||
0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5,
|
||||
0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
|
||||
0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6,
|
||||
0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
|
||||
0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
|
||||
0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9,
|
||||
0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9,
|
||||
0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
|
||||
|
||||
/* left blanking (24 pixels -> 240 Mcycles) */
|
||||
0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
|
||||
0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
|
||||
0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
|
||||
0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd,
|
||||
0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,
|
||||
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
|
||||
0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01,
|
||||
/* Vertical Interrupt triggered ? */
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
|
||||
0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb,
|
||||
0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
|
||||
0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd,
|
||||
0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,
|
||||
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
|
||||
0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01,
|
||||
/* V interrupt triggered (MD mode) */
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
|
||||
/* left border (13 pixels -> 130 Mcycles) , VDP status HBLANK flag cleared */
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
|
||||
0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
|
||||
0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
|
||||
/* remaining active display (240 pixels -> 2400 Mcycles) */
|
||||
0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
|
||||
0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
|
||||
0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
|
||||
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
|
||||
0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
|
||||
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
|
||||
0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
|
||||
0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
|
||||
0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
|
||||
0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
|
||||
0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
|
||||
0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
|
||||
0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d,
|
||||
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
|
||||
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
|
||||
0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
|
||||
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21,
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
|
||||
0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25,
|
||||
0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
|
||||
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
|
||||
0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
|
||||
0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
|
||||
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29,
|
||||
0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
|
||||
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
|
||||
0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
|
||||
0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
|
||||
0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
|
||||
0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
|
||||
0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
|
||||
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
|
||||
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
|
||||
0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
|
||||
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
|
||||
0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35,
|
||||
0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
|
||||
0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
|
||||
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39,
|
||||
0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
|
||||
0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
|
||||
0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
|
||||
0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
|
||||
0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d,
|
||||
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
|
||||
0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45,
|
||||
0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
|
||||
0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
|
||||
0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47,
|
||||
0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
|
||||
0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49,
|
||||
0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
|
||||
0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
|
||||
0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
|
||||
0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
|
||||
0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d,
|
||||
0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d,
|
||||
0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
|
||||
0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
|
||||
0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51,
|
||||
0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
|
||||
0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52,
|
||||
0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53,
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
|
||||
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56,
|
||||
0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
|
||||
0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
|
||||
0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59,
|
||||
0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59,
|
||||
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
|
||||
0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b,
|
||||
0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
|
||||
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d,
|
||||
0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d,
|
||||
0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
|
||||
0x5e, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61,
|
||||
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
|
||||
0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62,
|
||||
0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
|
||||
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
|
||||
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65,
|
||||
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67,
|
||||
0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68,
|
||||
0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69,
|
||||
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
|
||||
0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a,
|
||||
0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b,
|
||||
0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
|
||||
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d,
|
||||
0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d,
|
||||
0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
|
||||
0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
|
||||
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
|
||||
0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71,
|
||||
0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
|
||||
0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
|
||||
0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73,
|
||||
0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74,
|
||||
0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75,
|
||||
0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75,
|
||||
0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
|
||||
0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
|
||||
0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
|
||||
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79,
|
||||
0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
|
||||
0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a,
|
||||
0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
|
||||
0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
|
||||
0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d,
|
||||
0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d,
|
||||
0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
|
||||
0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
||||
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81,
|
||||
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
|
||||
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
|
||||
0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
|
||||
0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
|
||||
0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
|
||||
0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
|
||||
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
|
||||
0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
|
||||
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
|
||||
0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
|
||||
0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
|
||||
0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
|
||||
0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
|
||||
0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
|
||||
0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
|
||||
0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d,
|
||||
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
|
||||
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
|
||||
0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
|
||||
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21,
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
|
||||
0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25,
|
||||
0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
|
||||
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
|
||||
0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
|
||||
0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
|
||||
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29,
|
||||
0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
|
||||
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
|
||||
0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
|
||||
0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
|
||||
0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
|
||||
0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
|
||||
0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
|
||||
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
|
||||
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
|
||||
0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
|
||||
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
|
||||
0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35,
|
||||
0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
|
||||
0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
|
||||
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39,
|
||||
0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
|
||||
0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
|
||||
0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
|
||||
0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
|
||||
0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d,
|
||||
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
|
||||
0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45,
|
||||
0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
|
||||
0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
|
||||
0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47,
|
||||
0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
|
||||
0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49,
|
||||
0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
|
||||
0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
|
||||
0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
|
||||
0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
|
||||
0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d,
|
||||
0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d,
|
||||
0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
|
||||
0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
|
||||
0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51,
|
||||
0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
|
||||
0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52,
|
||||
0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53,
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
|
||||
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56,
|
||||
0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
|
||||
0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
|
||||
0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59,
|
||||
0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59,
|
||||
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
|
||||
0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b,
|
||||
0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
|
||||
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d,
|
||||
0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d,
|
||||
0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
|
||||
0x5e, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61,
|
||||
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
|
||||
0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62,
|
||||
0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
|
||||
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
|
||||
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65,
|
||||
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67,
|
||||
0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68,
|
||||
0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69,
|
||||
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
|
||||
0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a,
|
||||
0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b,
|
||||
0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
|
||||
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d,
|
||||
0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d,
|
||||
0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
|
||||
0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
|
||||
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
|
||||
0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71,
|
||||
0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
|
||||
0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
|
||||
0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73,
|
||||
0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74,
|
||||
0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75,
|
||||
0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75,
|
||||
0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
|
||||
0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
|
||||
0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
|
||||
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79,
|
||||
0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
|
||||
0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a,
|
||||
0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
|
||||
0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
|
||||
0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d,
|
||||
0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d,
|
||||
0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
|
||||
0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
||||
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81,
|
||||
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
|
||||
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
|
||||
0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
|
||||
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85,
|
||||
0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
|
||||
0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
|
||||
};
|
||||
|
||||
static const uint8 *hctab;
|
||||
static const uint8 cycle2hc40[3420] =
|
||||
{
|
||||
/* end of active display (16 pixels -> 128 Mcycles) , HINT triggered , Vcounter increment */
|
||||
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
|
||||
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
|
||||
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
|
||||
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
|
||||
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
|
||||
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
|
||||
|
||||
/* right border (14 pixels -> 112 Mcycles) */
|
||||
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
|
||||
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
|
||||
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
|
||||
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
|
||||
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
|
||||
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
|
||||
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
|
||||
|
||||
/* right blanking (9 pixels -> 72 Mcycles) , VDP status HBLANK flag set */
|
||||
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
|
||||
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
|
||||
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4,
|
||||
0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
|
||||
0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
|
||||
|
||||
/* horizontal sync (32 pixels -> 313 Mcycles) */
|
||||
0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
|
||||
0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
|
||||
0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8,
|
||||
0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9,
|
||||
0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea,
|
||||
0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb,
|
||||
0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
|
||||
0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec,
|
||||
0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed,
|
||||
0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee,
|
||||
0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef,
|
||||
0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
|
||||
0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
|
||||
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3,
|
||||
0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4,
|
||||
0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
|
||||
0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
|
||||
0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6,
|
||||
0xf6,
|
||||
|
||||
/* left blanking (32 pixels -> 259 Mcycles) */
|
||||
0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
|
||||
0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8,
|
||||
0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9,
|
||||
0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa,
|
||||
0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb,
|
||||
0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc,
|
||||
0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd,
|
||||
0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe,
|
||||
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
/* Vertical Interrupt triggered */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06,
|
||||
|
||||
/* left border (13 pixels -> 104 Mcycles) , VDP status HBLANK flag cleared */
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a,
|
||||
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
|
||||
/* remaining active display (304 pixels -> 2432 Mcycles) */
|
||||
0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e,
|
||||
0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12,
|
||||
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
|
||||
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
|
||||
0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16,
|
||||
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
|
||||
0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
|
||||
0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a,
|
||||
0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b,
|
||||
0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c,
|
||||
0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d,
|
||||
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e,
|
||||
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f,
|
||||
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21,
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23,
|
||||
0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25,
|
||||
0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26,
|
||||
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27,
|
||||
0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28,
|
||||
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29,
|
||||
0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a,
|
||||
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b,
|
||||
0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c,
|
||||
0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e,
|
||||
0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f,
|
||||
0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
|
||||
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32,
|
||||
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33,
|
||||
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34,
|
||||
0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35,
|
||||
0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37,
|
||||
0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38,
|
||||
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39,
|
||||
0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a,
|
||||
0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b,
|
||||
0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c,
|
||||
0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d,
|
||||
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43,
|
||||
0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45,
|
||||
0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x46,
|
||||
0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47,
|
||||
0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48,
|
||||
0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49,
|
||||
0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a,
|
||||
0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b,
|
||||
0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c,
|
||||
0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d,
|
||||
0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e,
|
||||
0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f,
|
||||
0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51,
|
||||
0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52,
|
||||
0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53,
|
||||
0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54,
|
||||
0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56,
|
||||
0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57,
|
||||
0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58,
|
||||
0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59,
|
||||
0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5a,
|
||||
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b,
|
||||
0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c,
|
||||
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d,
|
||||
0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e,
|
||||
0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f,
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61,
|
||||
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62,
|
||||
0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63,
|
||||
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64,
|
||||
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65,
|
||||
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67,
|
||||
0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68,
|
||||
0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69,
|
||||
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a,
|
||||
0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b,
|
||||
0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c,
|
||||
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d,
|
||||
0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e,
|
||||
0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f,
|
||||
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x70,
|
||||
0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71,
|
||||
0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72,
|
||||
0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73,
|
||||
0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74,
|
||||
0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75,
|
||||
0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76,
|
||||
0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77,
|
||||
0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78,
|
||||
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79,
|
||||
0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a,
|
||||
0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b,
|
||||
0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c,
|
||||
0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d,
|
||||
0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e,
|
||||
0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f,
|
||||
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80,
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81,
|
||||
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
|
||||
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84,
|
||||
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85,
|
||||
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x86,
|
||||
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87,
|
||||
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x88,
|
||||
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89,
|
||||
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a,
|
||||
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b,
|
||||
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8c,
|
||||
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8d,
|
||||
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e,
|
||||
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f,
|
||||
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90,
|
||||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91,
|
||||
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92,
|
||||
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93,
|
||||
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94,
|
||||
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x95,
|
||||
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x96, 0x96, 0x96, 0x96,
|
||||
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97,
|
||||
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, 0x98,
|
||||
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9a,
|
||||
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9c,
|
||||
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d,
|
||||
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e,
|
||||
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, 0x9f, 0x9f,
|
||||
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa0,
|
||||
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1,
|
||||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2,
|
||||
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3,
|
||||
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4,
|
||||
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4};
|
||||
|
||||
#endif /* _HVC_H_ */
|
||||
|
||||
|
121
source/input_hw/activator.c
Normal file
@ -0,0 +1,121 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Activator support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* 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 "shared.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
} activator[2];
|
||||
|
||||
void activator_reset(int index)
|
||||
{
|
||||
|
||||
activator[index].State = 0x40;
|
||||
activator[index].Counter = 0;
|
||||
}
|
||||
|
||||
static inline unsigned char activator_read(int port)
|
||||
{
|
||||
/* IR sensors 1-16 data (active low) */
|
||||
uint16 data = ~input.pad[port];
|
||||
|
||||
/* Device index */
|
||||
port = port >> 2;
|
||||
|
||||
/* D1 = D0 (data is ready) */
|
||||
uint8 temp = (activator[port].State & 0x01) << 1;
|
||||
|
||||
switch (activator[port].Counter)
|
||||
{
|
||||
case 0: /* x x x x 0 1 0 0 */
|
||||
temp |= 0x04;
|
||||
break;
|
||||
|
||||
case 1: /* x x l1 l2 l3 l4 1 1 */
|
||||
temp |= ((data << 2) & 0x3C);
|
||||
break;
|
||||
|
||||
case 2: /* x x l5 l6 l7 l8 0 0 */
|
||||
temp |= ((data >> 2) & 0x3C);
|
||||
break;
|
||||
|
||||
case 3: /* x x h1 h2 h3 h4 1 1 */
|
||||
temp |= ((data >> 6) & 0x3C);
|
||||
break;
|
||||
|
||||
case 4: /* x x h5 h6 h7 h8 0 0 */
|
||||
temp |= ((data >> 10) & 0x3C);
|
||||
break;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
static inline void activator_write(int index, unsigned char data, unsigned char mask)
|
||||
{
|
||||
/* update bits set as output only */
|
||||
data = (activator[index].State & ~mask) | (data & mask);
|
||||
|
||||
/* TH transitions */
|
||||
if ((activator[index].State ^ data) & 0x40)
|
||||
{
|
||||
/* reset sequence cycle */
|
||||
activator[index].Counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* D0 transitions */
|
||||
if ((activator[index].State ^ data) & 0x01)
|
||||
{
|
||||
/* increment sequence cycle */
|
||||
if (activator[index].Counter < 4)
|
||||
{
|
||||
activator[index].Counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* update internal state */
|
||||
activator[index].State = data;
|
||||
}
|
||||
|
||||
unsigned char activator_1_read(void)
|
||||
{
|
||||
return activator_read(0);
|
||||
}
|
||||
|
||||
unsigned char activator_2_read(void)
|
||||
{
|
||||
return activator_read(4);
|
||||
}
|
||||
|
||||
void activator_1_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
activator_write(0, data, mask);
|
||||
}
|
||||
|
||||
void activator_2_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
activator_write(1, data, mask);
|
||||
}
|
33
source/input_hw/activator.h
Normal file
@ -0,0 +1,33 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Activator support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _ACTIVATOR_H_
|
||||
#define _ACTIVATOR_H_
|
||||
|
||||
/* Function prototypes */
|
||||
extern void activator_reset(int index);
|
||||
extern unsigned char activator_1_read(void);
|
||||
extern unsigned char activator_2_read(void);
|
||||
extern void activator_1_write(unsigned char data, unsigned char mask);
|
||||
extern void activator_2_write(unsigned char data, unsigned char mask);
|
||||
|
||||
#endif
|
225
source/input_hw/gamepad.c
Normal file
@ -0,0 +1,225 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* 3-Buttons & 6-Buttons pad support (incl. 4-WayPlay & J-Cart handlers)
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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 "shared.h"
|
||||
#include "gamepad.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
uint8 Timeout;
|
||||
} gamepad[MAX_DEVICES];
|
||||
|
||||
static uint8 pad_index;
|
||||
|
||||
|
||||
void gamepad_reset(int port)
|
||||
{
|
||||
/* default state (Gouketsuji Ichizoku / Power Instinct, Samurai Spirits / Samurai Shodown) */
|
||||
gamepad[port].State = 0x40;
|
||||
gamepad[port].Counter = 0;
|
||||
gamepad[port].Timeout = 0;
|
||||
|
||||
/* reset pad index (4-WayPlay) */
|
||||
pad_index = 0;
|
||||
}
|
||||
|
||||
void gamepad_refresh(int port)
|
||||
{
|
||||
/* 6-buttons pad */
|
||||
if (gamepad[port].Timeout++ > 25)
|
||||
{
|
||||
gamepad[port].Counter = 0;
|
||||
gamepad[port].Timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned char gamepad_read(int port)
|
||||
{
|
||||
/* bit 7 is latched, returns current TH state */
|
||||
unsigned int data = (gamepad[port].State & 0x40) | 0x3F;
|
||||
|
||||
/* pad value */
|
||||
unsigned int val = input.pad[port];
|
||||
|
||||
/* get current step (TH state) */
|
||||
unsigned int step = (gamepad[port].Counter & 6) | ((data >> 6) & 1);
|
||||
|
||||
switch (step)
|
||||
{
|
||||
case 1: /*** First High ***/
|
||||
case 3: /*** Second High ***/
|
||||
case 5: /*** Third High ***/
|
||||
{
|
||||
/* TH = 1 : ?1CBRLDU */
|
||||
data &= ~(val & 0x3F);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0: /*** First low ***/
|
||||
case 2: /*** Second low ***/
|
||||
{
|
||||
/* TH = 0 : ?0SA00DU */
|
||||
data &= ~(val & 0x03);
|
||||
data &= ~((val >> 2) & 0x30);
|
||||
data &= ~0x0C;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 6buttons specific (taken from gen-hw.txt) */
|
||||
/* A 6-button gamepad allows the extra buttons to be read based on how */
|
||||
/* many times TH is switched from 1 to 0 (and not 0 to 1). Observe the */
|
||||
/* following sequence */
|
||||
/*
|
||||
TH = 1 : ?1CBRLDU 3-button pad return value
|
||||
TH = 0 : ?0SA00DU 3-button pad return value
|
||||
TH = 1 : ?1CBRLDU 3-button pad return value
|
||||
TH = 0 : ?0SA0000 D3-0 are forced to '0'
|
||||
TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0
|
||||
TH = 0 : ?0SA1111 D3-0 are forced to '1'
|
||||
*/
|
||||
case 4: /*** Third Low ***/
|
||||
{
|
||||
/* TH = 0 : ?0SA0000 D3-0 are forced to '0'*/
|
||||
data &= ~((val >> 2) & 0x30);
|
||||
data &= ~0x0F;
|
||||
break;
|
||||
}
|
||||
|
||||
case 6: /*** Fourth Low ***/
|
||||
{
|
||||
/* TH = 0 : ?0SA1111 D3-0 are forced to '1'*/
|
||||
data &= ~((val >> 2) & 0x30);
|
||||
break;
|
||||
}
|
||||
|
||||
case 7: /*** Fourth High ***/
|
||||
{
|
||||
/* TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0*/
|
||||
data &= ~(val & 0x30);
|
||||
data &= ~((val >> 8) & 0x0F);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void gamepad_write(int port, unsigned char data, unsigned char mask)
|
||||
{
|
||||
/* update bits set as output only */
|
||||
data = (gamepad[port].State & ~mask) | (data & mask);
|
||||
|
||||
if (input.dev[port] == DEVICE_PAD6B)
|
||||
{
|
||||
/* check TH transitions */
|
||||
if ((gamepad[port].State ^ data) & 0x40)
|
||||
{
|
||||
gamepad[port].Counter++;
|
||||
gamepad[port].Timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* update internal state */
|
||||
gamepad[port].State = data;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Default ports handlers */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned char gamepad_1_read(void)
|
||||
{
|
||||
return gamepad_read(0);
|
||||
}
|
||||
|
||||
unsigned char gamepad_2_read(void)
|
||||
{
|
||||
return gamepad_read(4);
|
||||
}
|
||||
|
||||
void gamepad_1_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
gamepad_write(0, data, mask);
|
||||
}
|
||||
|
||||
void gamepad_2_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
gamepad_write(4, data, mask);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 4-WayPlay ports handler */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned char wayplay_1_read(void)
|
||||
{
|
||||
if (pad_index < 4)
|
||||
{
|
||||
return gamepad_read(pad_index);
|
||||
}
|
||||
|
||||
/* multitap detection */
|
||||
return 0x70;
|
||||
}
|
||||
|
||||
unsigned char wayplay_2_read(void)
|
||||
{
|
||||
return 0x7F;
|
||||
}
|
||||
|
||||
void wayplay_1_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
if (pad_index < 4)
|
||||
{
|
||||
gamepad_write(pad_index, data, mask);
|
||||
}
|
||||
}
|
||||
|
||||
void wayplay_2_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
if ((mask & 0x70) == 0x70)
|
||||
{
|
||||
pad_index = (data & 0x70) >> 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* J-Cart memory handlers */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned int jcart_read(unsigned int address)
|
||||
{
|
||||
/* TH2 output read is fixed to zero (fixes Micro Machines 2) */
|
||||
return ((gamepad_read(5) & 0x7F) | ((gamepad_read(6) & 0x3F) << 8));
|
||||
}
|
||||
|
||||
void jcart_write(unsigned int address, unsigned int data)
|
||||
{
|
||||
gamepad_write(5, (data & 1) << 6, 0x40);
|
||||
gamepad_write(6, (data & 1) << 6, 0x40);
|
||||
return;
|
||||
}
|
41
source/input_hw/gamepad.h
Normal file
@ -0,0 +1,41 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* 3-Buttons & 6-Buttons pad support (incl. 4-WayPlay & J-Cart handlers)
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _GAMEPAD_H_
|
||||
#define _GAMEPAD_H_
|
||||
|
||||
/* Function prototypes */
|
||||
extern void gamepad_reset(int port);
|
||||
extern void gamepad_refresh(int port);
|
||||
extern unsigned char gamepad_1_read(void);
|
||||
extern unsigned char gamepad_2_read(void);
|
||||
extern void gamepad_1_write(unsigned char data, unsigned char mask);
|
||||
extern void gamepad_2_write(unsigned char data, unsigned char mask);
|
||||
extern unsigned char wayplay_1_read(void);
|
||||
extern unsigned char wayplay_2_read(void);
|
||||
extern void wayplay_1_write(unsigned char data, unsigned char mask);
|
||||
extern void wayplay_2_write(unsigned char data, unsigned char mask);
|
||||
extern unsigned int jcart_read(unsigned int address);
|
||||
extern void jcart_write(unsigned int address, unsigned int data);
|
||||
|
||||
#endif
|
338
source/input_hw/input.c
Normal file
@ -0,0 +1,338 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Input peripherals support
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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 "shared.h"
|
||||
#include "gamepad.h"
|
||||
#include "lightgun.h"
|
||||
#include "mouse.h"
|
||||
#include "activator.h"
|
||||
#include "xe_a1p.h"
|
||||
#include "teamplayer.h"
|
||||
#include "paddle.h"
|
||||
#include "sportspad.h"
|
||||
|
||||
t_input input;
|
||||
int old_system[2] = {-1,-1};
|
||||
|
||||
|
||||
void input_init(void)
|
||||
{
|
||||
int i;
|
||||
int player = 0;
|
||||
|
||||
for (i=0; i<MAX_DEVICES; i++)
|
||||
{
|
||||
input.dev[i] = NO_DEVICE;
|
||||
input.pad[i] = 0;
|
||||
}
|
||||
|
||||
/* PICO tablet & pen */
|
||||
if (system_hw == SYSTEM_PICO)
|
||||
{
|
||||
input.dev[0] = DEVICE_TABLET;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (input.system[0])
|
||||
{
|
||||
case SYSTEM_MS_GAMEPAD:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[0] = DEVICE_PAD2B;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MD_GAMEPAD:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[0] = config.input[player].padtype;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MOUSE:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[0] = DEVICE_MOUSE;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_ACTIVATOR:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[0] = DEVICE_ACTIVATOR;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_XE_A1P:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[0] = DEVICE_XE_A1P;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
{
|
||||
for (i=0; i< 4; i++)
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[i] = config.input[player].padtype;
|
||||
player++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
{
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[i] = config.input[player].padtype;
|
||||
player++;
|
||||
}
|
||||
teamplayer_init(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_LIGHTPHASER:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[0] = DEVICE_LIGHTGUN;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_PADDLE:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[0] = DEVICE_PADDLE;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_SPORTSPAD:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[0] = DEVICE_SPORTSPAD;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (input.system[1])
|
||||
{
|
||||
case SYSTEM_MS_GAMEPAD:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_PAD2B;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MD_GAMEPAD:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[4] = config.input[player].padtype;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MOUSE:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_MOUSE;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_ACTIVATOR:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_ACTIVATOR;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MENACER:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_LIGHTGUN;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_JUSTIFIER:
|
||||
{
|
||||
for (i=4; i<6; i++)
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[i] = DEVICE_LIGHTGUN;
|
||||
player++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
{
|
||||
for (i=4; i<8; i++)
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[i] = config.input[player].padtype;
|
||||
player++;
|
||||
}
|
||||
teamplayer_init(1);
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_LIGHTPHASER:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_LIGHTGUN;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_PADDLE:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_PADDLE;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_SPORTSPAD:
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_SPORTSPAD;
|
||||
player++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* J-CART */
|
||||
if (cart.special & HW_J_CART)
|
||||
{
|
||||
/* two additional gamepads */
|
||||
for (i=5; i<7; i++)
|
||||
{
|
||||
if (player == MAX_INPUTS) return;
|
||||
input.dev[i] = config.input[player].padtype;
|
||||
player ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void input_reset(void)
|
||||
{
|
||||
/* Reset input devices */
|
||||
int i;
|
||||
for (i=0; i<MAX_DEVICES; i++)
|
||||
{
|
||||
switch (input.dev[i])
|
||||
{
|
||||
case DEVICE_PAD2B:
|
||||
case DEVICE_PAD3B:
|
||||
case DEVICE_PAD6B:
|
||||
{
|
||||
gamepad_reset(i);
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_LIGHTGUN:
|
||||
{
|
||||
lightgun_reset(i);
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_MOUSE:
|
||||
{
|
||||
mouse_reset(i);
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_ACTIVATOR:
|
||||
{
|
||||
activator_reset(i >> 2);
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_XE_A1P:
|
||||
{
|
||||
xe_a1p_reset();
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_PADDLE:
|
||||
{
|
||||
paddle_reset(i >> 2);
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_SPORTSPAD:
|
||||
{
|
||||
sportspad_reset(i >> 2);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Team Player */
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
if (input.system[i] == SYSTEM_TEAMPLAYER)
|
||||
{
|
||||
teamplayer_reset(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void input_refresh(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<MAX_DEVICES; i++)
|
||||
{
|
||||
switch (input.dev[i])
|
||||
{
|
||||
case DEVICE_PAD6B:
|
||||
{
|
||||
gamepad_refresh(i);
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_LIGHTGUN:
|
||||
{
|
||||
lightgun_refresh(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
128
source/input_hw/input.h
Normal file
@ -0,0 +1,128 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Input peripherals support
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _INPUT_H_
|
||||
#define _INPUT_H_
|
||||
|
||||
/* Max. number of devices */
|
||||
#define MAX_DEVICES (8)
|
||||
|
||||
/* Ports configuration */
|
||||
#define NO_SYSTEM (0) /* unconnected port*/
|
||||
#define SYSTEM_MD_GAMEPAD (1) /* single 3-buttons or 6-buttons Control Pad */
|
||||
#define SYSTEM_MOUSE (2) /* Sega Mouse */
|
||||
#define SYSTEM_MENACER (3) /* Sega Menacer (port B only) */
|
||||
#define SYSTEM_JUSTIFIER (4) /* Konami Justifiers (port B only) */
|
||||
#define SYSTEM_XE_A1P (5) /* XE-A1P analog controller (port A only) */
|
||||
#define SYSTEM_ACTIVATOR (6) /* Sega Activator */
|
||||
#define SYSTEM_MS_GAMEPAD (7) /* single 2-buttons Control Pad (Master System) */
|
||||
#define SYSTEM_LIGHTPHASER (8) /* Sega Light Phaser (Master System) */
|
||||
#define SYSTEM_PADDLE (9) /* Sega Paddle Control (Master System) */
|
||||
#define SYSTEM_SPORTSPAD (10) /* Sega Sports Pad (Master System) */
|
||||
#define SYSTEM_TEAMPLAYER (11) /* Sega TeamPlayer */
|
||||
#define SYSTEM_WAYPLAY (12) /* EA 4-Way Play (use both ports) */
|
||||
|
||||
/* Device type */
|
||||
#define DEVICE_PAD3B (0x00) /* 3-buttons Control Pad */
|
||||
#define DEVICE_PAD6B (0x01) /* 6-buttons Control Pad */
|
||||
#define DEVICE_MOUSE (0x02) /* Sega Mouse */
|
||||
#define DEVICE_XE_A1P (0x03) /* XE-A1P analog controller */
|
||||
#define DEVICE_ACTIVATOR (0x04) /* Activator */
|
||||
#define DEVICE_LIGHTGUN (0x05) /* Sega Light Phaser, Menacer or Konami Justifiers */
|
||||
#define DEVICE_PAD2B (0x06) /* 2-buttons Control Pad */
|
||||
#define DEVICE_PADDLE (0x07) /* Sega Paddle Control */
|
||||
#define DEVICE_SPORTSPAD (0x08) /* Sega Sports Pad */
|
||||
#define DEVICE_TABLET (0x09) /* PICO tablet & pen */
|
||||
#define NO_DEVICE (0xff) /* unconnected device */
|
||||
|
||||
/* Default Input bitmasks */
|
||||
#define INPUT_MODE (0x0800)
|
||||
#define INPUT_X (0x0400)
|
||||
#define INPUT_Y (0x0200)
|
||||
#define INPUT_Z (0x0100)
|
||||
#define INPUT_START (0x0080)
|
||||
#define INPUT_A (0x0040)
|
||||
#define INPUT_C (0x0020)
|
||||
#define INPUT_B (0x0010)
|
||||
#define INPUT_RIGHT (0x0008)
|
||||
#define INPUT_LEFT (0x0004)
|
||||
#define INPUT_DOWN (0x0002)
|
||||
#define INPUT_UP (0x0001)
|
||||
|
||||
/* Master System specific bitmasks */
|
||||
#define INPUT_BUTTON2 (0x0020)
|
||||
#define INPUT_BUTTON1 (0x0010)
|
||||
|
||||
/* Mouse specific bitmask */
|
||||
#define INPUT_MOUSE_CENTER (0x0040)
|
||||
#define INPUT_MOUSE_RIGHT (0x0020)
|
||||
#define INPUT_MOUSE_LEFT (0x0010)
|
||||
|
||||
/* XE-1AP specific bitmask */
|
||||
#define INPUT_XE_E1 (0x0800)
|
||||
#define INPUT_XE_E2 (0x0400)
|
||||
#define INPUT_XE_START (0x0200)
|
||||
#define INPUT_XE_SELECT (0x0100)
|
||||
#define INPUT_XE_A (0x0080)
|
||||
#define INPUT_XE_B (0x0040)
|
||||
#define INPUT_XE_C (0x0020)
|
||||
#define INPUT_XE_D (0x0010)
|
||||
|
||||
/* Activator specific bitmasks */
|
||||
#define INPUT_ACTIVATOR_8U (0x8000)
|
||||
#define INPUT_ACTIVATOR_8L (0x4000)
|
||||
#define INPUT_ACTIVATOR_7U (0x2000)
|
||||
#define INPUT_ACTIVATOR_7L (0x1000)
|
||||
#define INPUT_ACTIVATOR_6U (0x0800)
|
||||
#define INPUT_ACTIVATOR_6L (0x0400)
|
||||
#define INPUT_ACTIVATOR_5U (0x0200)
|
||||
#define INPUT_ACTIVATOR_5L (0x0100)
|
||||
#define INPUT_ACTIVATOR_4U (0x0080)
|
||||
#define INPUT_ACTIVATOR_4L (0x0040)
|
||||
#define INPUT_ACTIVATOR_3U (0x0020)
|
||||
#define INPUT_ACTIVATOR_3L (0x0010)
|
||||
#define INPUT_ACTIVATOR_2U (0x0008)
|
||||
#define INPUT_ACTIVATOR_2L (0x0004)
|
||||
#define INPUT_ACTIVATOR_1U (0x0002)
|
||||
#define INPUT_ACTIVATOR_1L (0x0001)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8 system[2]; /* can be one of the SYSTEM_* values */
|
||||
uint8 dev[MAX_DEVICES]; /* can be one of the DEVICE_* values */
|
||||
uint16 pad[MAX_DEVICES]; /* digital inputs (any of INPUT_* values) */
|
||||
int16 analog[MAX_DEVICES][2]; /* analog inputs (x/y) */
|
||||
uint8 x_offset; /* gun horizontal offset */
|
||||
uint8 y_offset; /* gun vertical offset */
|
||||
} t_input;
|
||||
|
||||
/* Global variables */
|
||||
extern t_input input;
|
||||
extern int old_system[2];
|
||||
|
||||
/* Function prototypes */
|
||||
extern void input_init(void);
|
||||
extern void input_reset(void);
|
||||
extern void input_refresh(void);
|
||||
|
||||
#endif
|
216
source/input_hw/lightgun.c
Normal file
@ -0,0 +1,216 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Light Phaser, Menacer & Konami Justifiers support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* 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 "shared.h"
|
||||
|
||||
/************************************************************************************/
|
||||
/* */
|
||||
/* H-counter values returned in H40 & H32 modes */
|
||||
/* */
|
||||
/* Inside VDP, dot counter register is 9-bit, with only upper 8 bits being returned */
|
||||
/* */
|
||||
/* The number of dots per raster line is 342 in H32 mode and 420 in H40 mode */
|
||||
/* */
|
||||
/************************************************************************************/
|
||||
|
||||
static const uint8 hc_256[171] =
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93,
|
||||
0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
static const uint8 hc_320[210] =
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
|
||||
0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED,
|
||||
0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD,
|
||||
0xFE, 0xFF
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Port;
|
||||
} lightgun;
|
||||
|
||||
|
||||
void lightgun_reset(int port)
|
||||
{
|
||||
input.analog[port][0] = bitmap.viewport.w >> 1;
|
||||
input.analog[port][1] = bitmap.viewport.h >> 1;
|
||||
lightgun.State = 0x40;
|
||||
lightgun.Port = 4;
|
||||
}
|
||||
|
||||
void lightgun_refresh(int port)
|
||||
{
|
||||
/* Check that lightgun is enabled */
|
||||
if (port == lightgun.Port)
|
||||
{
|
||||
/* check if line falls within current gun Y position */
|
||||
if ((input.analog[port][1] == v_counter + input.y_offset))
|
||||
{
|
||||
/* HL enabled ? */
|
||||
if (io_reg[5] & 0x80)
|
||||
{
|
||||
/* External Interrupt ? */
|
||||
if (reg[11] & 0x08)
|
||||
{
|
||||
m68k_irq_state |= 0x12;
|
||||
}
|
||||
|
||||
/* HV Counter Latch:
|
||||
1) some games does not enable HVC latch but instead use bigger X offset
|
||||
--> we force the HV counter value read by the gun routine
|
||||
2) for games using H40 mode, the gun routine scales up the Hcounter value
|
||||
--> H-Counter range is approx. 290 dot clocks
|
||||
*/
|
||||
hvc_latch = 0x10000 | (v_counter << 8);
|
||||
if (reg[12] & 1)
|
||||
{
|
||||
hvc_latch |= hc_320[((input.analog[port][0] * 290) / (2 * 320) + input.x_offset) % 210];
|
||||
}
|
||||
else
|
||||
{
|
||||
hvc_latch |= hc_256[(input.analog[port][0] / 2 + input.x_offset) % 171];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Sega Phaser */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static inline unsigned char phaser_read(int port)
|
||||
{
|
||||
/* FIRE button status (active low) */
|
||||
unsigned char temp = ~(input.pad[port] & 0x10);
|
||||
|
||||
/* Check that TH is set as an input */
|
||||
if (io_reg[0] & (0x02 << (port >> 1)))
|
||||
{
|
||||
/* Get current X position (phaser is only used in MS compatiblity mode) */
|
||||
int hcounter = hctab[(mcycles_z80 + Z80_CYCLE_OFFSET) % MCYCLES_PER_LINE];
|
||||
|
||||
/* Compare with gun position */
|
||||
int dx = input.analog[port][0] - (hcounter << 1);
|
||||
int dy = input.analog[port][1] - (v_counter);
|
||||
|
||||
/* Check if current pixel is within lightgun spot ? */
|
||||
if ((abs(dy) <= 5) && (abs(dx) <= 60))
|
||||
{
|
||||
/* set TH low */
|
||||
temp &= ~0x40;
|
||||
|
||||
/* prevents multiple latch at each port read */
|
||||
if (lightgun.State)
|
||||
{
|
||||
/* latch estimated HC value */
|
||||
hvc_latch = 0x10000 | (input.x_offset + (input.analog[port][0] >> 1));
|
||||
lightgun.State = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightgun.State = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return temp & 0x7F;
|
||||
}
|
||||
|
||||
unsigned char phaser_1_read(void)
|
||||
{
|
||||
return phaser_read(0);
|
||||
}
|
||||
|
||||
unsigned char phaser_2_read(void)
|
||||
{
|
||||
return phaser_read(4);
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Sega Menacer */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned char menacer_read(void)
|
||||
{
|
||||
/* Return START,A,B,C buttons status in D0-D3 (active high) */
|
||||
/* TL & TR pins always return 0 (normally set as output) */
|
||||
return ((input.pad[4] >> 4) & 0x0F);
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Konami Justifiers */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned char justifier_read(void)
|
||||
{
|
||||
/* Gun detection */
|
||||
if (lightgun.State & 0x40)
|
||||
{
|
||||
return 0x30;
|
||||
}
|
||||
|
||||
/* Return A & START button status in D0-D1 (active low) */
|
||||
/* TL & TR pins should always return 1 (normally set as output) */
|
||||
/* LEFT & RIGHT pins should always return 0 */
|
||||
return (((~input.pad[lightgun.Port] >> 6) & 0x03) | 0x70);
|
||||
}
|
||||
|
||||
void justifier_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
/* update bits set as output only */
|
||||
data = (lightgun.State & ~mask) | (data & mask);
|
||||
|
||||
/* gun index */
|
||||
lightgun.Port = 4 + ((data >> 5) & 1);
|
||||
|
||||
/* update internal state */
|
||||
lightgun.State = data;
|
||||
}
|
35
source/input_hw/lightgun.h
Normal file
@ -0,0 +1,35 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Light Phaser, Menacer & Konami Justifiers support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _LIGHTGUN_H_
|
||||
#define _LIGHTGUN_H_
|
||||
|
||||
/* Input devices port handlers */
|
||||
extern void lightgun_reset(int index);
|
||||
extern void lightgun_refresh(int port);
|
||||
extern unsigned char phaser_1_read(void);
|
||||
extern unsigned char phaser_2_read(void);
|
||||
extern unsigned char menacer_read(void);
|
||||
extern unsigned char justifier_read(void);
|
||||
extern void justifier_write(unsigned char data, unsigned char mask);
|
||||
|
||||
#endif
|
153
source/input_hw/mouse.c
Normal file
@ -0,0 +1,153 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Mouse support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* 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 "shared.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
uint8 Wait;
|
||||
uint8 Port;
|
||||
} mouse;
|
||||
|
||||
void mouse_reset(int port)
|
||||
{
|
||||
input.analog[port][0] = 0;
|
||||
input.analog[port][1] = 0;
|
||||
mouse.State = 0x60;
|
||||
mouse.Counter = 0;
|
||||
mouse.Wait = 0;
|
||||
mouse.Port = port;
|
||||
}
|
||||
|
||||
unsigned char mouse_read()
|
||||
{
|
||||
unsigned int temp = 0x00;
|
||||
int x = input.analog[mouse.Port][0];
|
||||
int y = input.analog[mouse.Port][1];
|
||||
|
||||
switch (mouse.Counter)
|
||||
{
|
||||
case 0: /* initial */
|
||||
temp = 0x00;
|
||||
break;
|
||||
|
||||
case 1: /* xxxx1011 */
|
||||
temp = 0x0B;
|
||||
break;
|
||||
|
||||
case 2: /* xxxx1111 */
|
||||
temp = 0x0F;
|
||||
break;
|
||||
|
||||
case 3: /* xxxx1111 */
|
||||
temp = 0x0F;
|
||||
break;
|
||||
|
||||
case 4: /* Axis sign & overflow (not emulated) bits */
|
||||
temp |= (x < 0);
|
||||
temp |= (y < 0) << 1;
|
||||
/*
|
||||
temp |= (abs(x) > 255) << 2;
|
||||
temp |= (abs(y) > 255) << 3;
|
||||
*/
|
||||
break;
|
||||
|
||||
case 5: /* START, A, B, C buttons state (active high) */
|
||||
temp = (input.pad[mouse.Port] >> 4) & 0x0F;
|
||||
break;
|
||||
|
||||
case 6: /* X Axis MSB */
|
||||
temp = (x >> 4) & 0x0F;
|
||||
break;
|
||||
|
||||
case 7: /* X Axis LSB */
|
||||
temp = (x & 0x0F);
|
||||
break;
|
||||
|
||||
case 8: /* Y Axis MSB */
|
||||
temp = (y >> 4) & 0x0F;
|
||||
break;
|
||||
|
||||
case 9: /* Y Axis LSB */
|
||||
temp = (y & 0x0F);
|
||||
break;
|
||||
}
|
||||
|
||||
/* TL = busy status */
|
||||
if (mouse.Wait)
|
||||
{
|
||||
/* wait before ACK, fix some buggy mouse routine (Shangai 2, Wack World,...) */
|
||||
mouse.Wait = 0;
|
||||
|
||||
/* TL = !TR */
|
||||
temp |= (~mouse.State & 0x20) >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TL = TR (data is ready) */
|
||||
temp |= (mouse.State & 0x20) >> 1;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
void mouse_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
/* update bits set as output only */
|
||||
data = (mouse.State & ~mask) | (data & mask);
|
||||
|
||||
if (mouse.Counter == 0)
|
||||
{
|
||||
/* wait for TH 1->0 transition */
|
||||
if ((mouse.State & 0x40) && !(data & 0x40))
|
||||
{
|
||||
/* start acquisition */
|
||||
mouse.Counter = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TR handshake */
|
||||
if ((mouse.State ^ data) & 0x20)
|
||||
{
|
||||
/* increment phase */
|
||||
if (mouse.Counter < 10)
|
||||
{
|
||||
mouse.Counter++;
|
||||
}
|
||||
|
||||
/* input latency */
|
||||
mouse.Wait = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* end of acquisition (TH=1) */
|
||||
if (data & 0x40)
|
||||
{
|
||||
mouse.Counter = 0;
|
||||
}
|
||||
|
||||
/* update internal state */
|
||||
mouse.State = data;
|
||||
}
|
31
source/input_hw/mouse.h
Normal file
@ -0,0 +1,31 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Mouse support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _MOUSE_H_
|
||||
#define _MOUSE_H_
|
||||
|
||||
/* Function prototypes */
|
||||
extern void mouse_reset(int port);
|
||||
extern unsigned char mouse_read(void);
|
||||
extern void mouse_write(unsigned char data, unsigned char mask);
|
||||
|
||||
#endif
|
95
source/input_hw/paddle.c
Normal file
@ -0,0 +1,95 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Paddle Control support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* 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 "shared.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 State;
|
||||
} paddle[2];
|
||||
|
||||
void paddle_reset(int index)
|
||||
{
|
||||
input.analog[index << 2][0] = 128;
|
||||
paddle[index].State = 0x40;
|
||||
}
|
||||
|
||||
static inline unsigned char paddle_read(int port)
|
||||
{
|
||||
/* FIRE button status (active low) */
|
||||
unsigned char temp = ~(input.pad[port] & 0x10);
|
||||
|
||||
/* Pad index */
|
||||
int index = port >> 2;
|
||||
|
||||
/* Clear low bits */
|
||||
temp &= 0x70;
|
||||
|
||||
/* Japanese model: automatic flip-flop */
|
||||
if (region_code < REGION_USA)
|
||||
{
|
||||
paddle[index].State ^= 0x40;
|
||||
}
|
||||
|
||||
if (paddle[index].State & 0x40)
|
||||
{
|
||||
/* return higher bits */
|
||||
temp |= (input.analog[port][0] >> 4) & 0x0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* return lower bits */
|
||||
temp |= input.analog[port][0] & 0x0F;
|
||||
|
||||
/* set TR low */
|
||||
temp &= ~0x20;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
static inline void paddle_write(int index, unsigned char data, unsigned char mask)
|
||||
{
|
||||
/* update bits set as output only */
|
||||
paddle[index].State = (paddle[index].State & ~mask) | (data & mask);
|
||||
}
|
||||
|
||||
|
||||
unsigned char paddle_1_read(void)
|
||||
{
|
||||
return paddle_read(0);
|
||||
}
|
||||
|
||||
unsigned char paddle_2_read(void)
|
||||
{
|
||||
return paddle_read(4);
|
||||
}
|
||||
|
||||
void paddle_1_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
paddle_write(0, data, mask);
|
||||
}
|
||||
|
||||
void paddle_2_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
paddle_write(1, data, mask);
|
||||
}
|
33
source/input_hw/paddle.h
Normal file
@ -0,0 +1,33 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Paddle Control support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _PADDLE_H_
|
||||
#define _PADDLE_H_
|
||||
|
||||
/* Function prototypes */
|
||||
extern void paddle_reset(int index);
|
||||
extern unsigned char paddle_1_read(void);
|
||||
extern unsigned char paddle_2_read(void);
|
||||
extern void paddle_1_write(unsigned char data, unsigned char mask);
|
||||
extern void paddle_2_write(unsigned char data, unsigned char mask);
|
||||
|
||||
#endif
|
118
source/input_hw/sportspad.c
Normal file
@ -0,0 +1,118 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Sports Pad support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* 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 "shared.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
} sportspad[2];
|
||||
|
||||
void sportspad_reset(int index)
|
||||
{
|
||||
input.analog[index << 2][0] = 128;
|
||||
input.analog[index << 2][1] = 128;
|
||||
sportspad[index].State = 0x40;
|
||||
sportspad[index].Counter = 0;
|
||||
}
|
||||
|
||||
static inline unsigned char sportspad_read(int port)
|
||||
{
|
||||
/* Buttons 1(B) & 2(C) status (active low) */
|
||||
unsigned char temp = ~(input.pad[port] & 0x30);
|
||||
|
||||
/* Pad index */
|
||||
int index = port >> 2;
|
||||
|
||||
/* Clear low bits */
|
||||
temp &= 0x70;
|
||||
|
||||
/* Detect current state */
|
||||
switch (sportspad[index].Counter & 3)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
/* X position high bits */
|
||||
temp |= (input.analog[port][0] >> 4) & 0x0F;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
/* X position low bits */
|
||||
temp |= input.analog[port][0] & 0x0F;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
/* Y position high bits */
|
||||
temp |= (input.analog[port][1] >> 4) & 0x0F;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Y position low bits */
|
||||
temp |= input.analog[port][1] & 0x0F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
static inline void sportspad_write(int index, unsigned char data, unsigned char mask)
|
||||
{
|
||||
/* update bits set as output only */
|
||||
data = (sportspad[index].State & ~mask) | (data & mask);
|
||||
|
||||
/* check TH transitions */
|
||||
if ((data ^ sportspad[index].State) & 0x40)
|
||||
{
|
||||
sportspad[index].Counter++;
|
||||
}
|
||||
|
||||
/* update internal state */
|
||||
sportspad[index].State = data;
|
||||
}
|
||||
|
||||
unsigned char sportspad_1_read(void)
|
||||
{
|
||||
return sportspad_read(0);
|
||||
}
|
||||
|
||||
unsigned char sportspad_2_read(void)
|
||||
{
|
||||
return sportspad_read(4);
|
||||
}
|
||||
|
||||
void sportspad_1_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
sportspad_write(0, data, mask);
|
||||
}
|
||||
|
||||
void sportspad_2_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
sportspad_write(1, data, mask);
|
||||
}
|
33
source/input_hw/sportspad.h
Normal file
@ -0,0 +1,33 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Sega Sports Pad support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _SPORTSPAD_H_
|
||||
#define _SPORTSPAD_H_
|
||||
|
||||
/* Function prototypes */
|
||||
extern void sportspad_reset(int index);
|
||||
extern unsigned char sportspad_1_read(void);
|
||||
extern unsigned char sportspad_2_read(void);
|
||||
extern void sportspad_1_write(unsigned char data, unsigned char mask);
|
||||
extern void sportspad_2_write(unsigned char data, unsigned char mask);
|
||||
|
||||
#endif
|
160
source/input_hw/teamplayer.c
Normal file
@ -0,0 +1,160 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Team Player support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* 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 "shared.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
uint8 Table[12];
|
||||
} teamplayer[2];
|
||||
|
||||
|
||||
void teamplayer_init(int port)
|
||||
{
|
||||
int i,padnum;
|
||||
int index = 0;
|
||||
|
||||
/* this table determines which gamepad input should be returned during acquisition sequence
|
||||
index = teamplayer read table index: 0=1st read, 1=2nd read, ...
|
||||
table = high bits are pad index, low bits are pad input shift: 0=RLDU, 4=SABC, 8=MXYZ
|
||||
*/
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
padnum = (4 * port) + i;
|
||||
if (input.dev[padnum] == DEVICE_PAD3B)
|
||||
{
|
||||
padnum = padnum << 4;
|
||||
teamplayer[port].Table[index++] = padnum;
|
||||
teamplayer[port].Table[index++] = padnum | 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
padnum = padnum << 4;
|
||||
teamplayer[port].Table[index++] = padnum;
|
||||
teamplayer[port].Table[index++] = padnum | 4;
|
||||
teamplayer[port].Table[index++] = padnum | 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void teamplayer_reset(int port)
|
||||
{
|
||||
teamplayer[port].State = 0x60; /* TH = 1, TR = 1 */
|
||||
teamplayer[port].Counter = 0;
|
||||
}
|
||||
|
||||
static inline unsigned int teamplayer_read(int port)
|
||||
{
|
||||
unsigned int counter = teamplayer[port].Counter;
|
||||
|
||||
/* acquisition sequence */
|
||||
switch (counter)
|
||||
{
|
||||
case 0: /* initial state: TH = 1, TR = 1 -> RLDU = 0011 */
|
||||
{
|
||||
return 0x73;
|
||||
}
|
||||
|
||||
case 1: /* start request: TH = 0, TR = 1 -> RLDU = 1111 */
|
||||
{
|
||||
return 0x3F;
|
||||
}
|
||||
|
||||
case 2:
|
||||
case 3: /* ack request: TH=0, TR=0/1 -> RLDU = 0000 */
|
||||
{
|
||||
/* TL should match TR */
|
||||
return ((teamplayer[port].State & 0x20) >> 1);
|
||||
}
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7: /* PAD type */
|
||||
{
|
||||
unsigned int retval = input.dev[(port << 2) + (counter - 4)];
|
||||
|
||||
/* TL should match TR */
|
||||
return (((teamplayer[port].State & 0x20) >> 1) | retval);
|
||||
}
|
||||
|
||||
default: /* PAD status */
|
||||
{
|
||||
unsigned int retval = 0x0F;
|
||||
|
||||
/* SEGA teamplayer returns successively PAD1 -> PAD2 -> PAD3 -> PAD4 inputs */
|
||||
unsigned int padnum = teamplayer[port].Table[counter - 8] >> 4;
|
||||
|
||||
/* Each PAD inputs is obtained through 2 or 3 sequential reads: RLDU -> SACB -> MXYZ */
|
||||
retval &= ~(input.pad[padnum] >> (teamplayer[port].Table[counter - 8] & 0x0F));
|
||||
|
||||
/* TL should match TR */
|
||||
return (((teamplayer[port].State & 0x20) >> 1) | retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void teamplayer_write(int port, unsigned char data, unsigned char mask)
|
||||
{
|
||||
/* update bits set as output only */
|
||||
unsigned int state = (teamplayer[port].State & ~mask) | (data & mask);
|
||||
|
||||
/* TH & TR handshaking */
|
||||
if ((teamplayer[port].State ^ state) & 0x60)
|
||||
{
|
||||
if (state & 0x40)
|
||||
{
|
||||
/* TH high -> reset counter */
|
||||
teamplayer[port].Counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* increment counter */
|
||||
teamplayer[port].Counter++;
|
||||
}
|
||||
|
||||
/* update internal state */
|
||||
teamplayer[port].State = state;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char teamplayer_1_read(void)
|
||||
{
|
||||
return teamplayer_read(0);
|
||||
}
|
||||
|
||||
unsigned char teamplayer_2_read(void)
|
||||
{
|
||||
return teamplayer_read(1);
|
||||
}
|
||||
|
||||
void teamplayer_1_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
teamplayer_write(0, data, mask);
|
||||
}
|
||||
|
||||
void teamplayer_2_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
teamplayer_write(1, data, mask);
|
||||
}
|
34
source/input_hw/teamplayer.h
Normal file
@ -0,0 +1,34 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Team Player support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _TEAMPLAYER_H_
|
||||
#define _TEAMPLAYER_H_
|
||||
|
||||
/* Function prototypes */
|
||||
extern void teamplayer_init(int port);
|
||||
extern void teamplayer_reset(int port);
|
||||
extern unsigned char teamplayer_1_read(void);
|
||||
extern unsigned char teamplayer_2_read(void);
|
||||
extern void teamplayer_1_write(unsigned char data, unsigned char mask);
|
||||
extern void teamplayer_2_write(unsigned char data, unsigned char mask);
|
||||
|
||||
#endif
|
144
source/input_hw/xe_a1p.c
Normal file
@ -0,0 +1,144 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* XE-A1P analog controller support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* 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 "shared.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
uint8 Latency;
|
||||
} xe_a1p;
|
||||
|
||||
void xe_a1p_reset(void)
|
||||
{
|
||||
input.analog[0][0] = 128;
|
||||
input.analog[0][1] = 128;
|
||||
input.analog[1][0] = 128;
|
||||
xe_a1p.State = 0x40;
|
||||
xe_a1p.Counter = 0;
|
||||
xe_a1p.Latency = 0;
|
||||
}
|
||||
|
||||
unsigned char xe_a1p_read()
|
||||
{
|
||||
unsigned int temp = 0x40;
|
||||
|
||||
/* Left Stick X & Y analog values (bidirectional) */
|
||||
int x = input.analog[0][0];
|
||||
int y = input.analog[0][1];
|
||||
|
||||
/* Right Stick X or Y value (unidirectional) */
|
||||
int z = input.analog[1][0];
|
||||
|
||||
/* Buttons status (active low) */
|
||||
uint16 pad = ~input.pad[0];
|
||||
|
||||
/* Current 4-bit data cycle */
|
||||
/* There are eight internal data cycle for each 5 acquisition sequence */
|
||||
/* First 4 return the same 4-bit data, next 4 return next 4-bit data */
|
||||
switch (xe_a1p.Counter >> 2)
|
||||
{
|
||||
case 0:
|
||||
temp |= ((pad >> 8) & 0x0F); /* E1 E2 Start Select */
|
||||
break;
|
||||
case 1:
|
||||
temp |= ((pad >> 4) & 0x0F); /* A B C D */
|
||||
break;
|
||||
case 2:
|
||||
temp |= ((x >> 4) & 0x0F);
|
||||
break;
|
||||
case 3:
|
||||
temp |= ((y >> 4) & 0x0F);
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
case 5:
|
||||
temp |= ((z >> 4) & 0x0F);
|
||||
break;
|
||||
case 6:
|
||||
temp |= (x & 0x0F);
|
||||
break;
|
||||
case 7:
|
||||
temp |= (y & 0x0F);
|
||||
break;
|
||||
case 8:
|
||||
break;
|
||||
case 9:
|
||||
temp |= (z & 0x0F);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get current internal cycle (0-7) */
|
||||
unsigned int cycle = xe_a1p.Counter & 7;
|
||||
|
||||
/* TL indicates which part of data is returned (0=1st part, 1=2nd part) */
|
||||
temp |= ((cycle & 4) << 2);
|
||||
|
||||
/* TR indicates if data is ready (0=ready, 1=not ready) */
|
||||
/* Fastest One input routine actually expects this bit to switch between 0 & 1 */
|
||||
/* so we make the first read of a data cycle return 1 then 0 for remaining reads */
|
||||
temp |= (!(cycle & 3) << 5);
|
||||
|
||||
/* Automatically increment data cycle on each read (within current acquisition sequence) */
|
||||
cycle = (cycle + 1) & 7;
|
||||
|
||||
/* Update internal cycle counter */
|
||||
xe_a1p.Counter = (xe_a1p.Counter & ~7) | cycle;
|
||||
|
||||
/* Update internal latency on each read */
|
||||
xe_a1p.Latency++;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
void xe_a1p_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
/* update bits set as output only */
|
||||
data = (xe_a1p.State & ~mask) | (data & mask);
|
||||
|
||||
/* look for TH 1->0 transitions */
|
||||
if (!(data & 0x40) && (xe_a1p.State & 0x40))
|
||||
{
|
||||
/* reset acquisition cycle */
|
||||
xe_a1p.Latency = xe_a1p.Counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* some games immediately write new data to TH */
|
||||
/* so we make sure first sequence has actually been handled */
|
||||
if (xe_a1p.Latency > 2)
|
||||
{
|
||||
/* next acquisition sequence */
|
||||
xe_a1p.Counter = (xe_a1p.Counter & ~7) + 8;
|
||||
|
||||
/* 5 sequence max with 8 cycles each */
|
||||
if (xe_a1p.Counter > 32)
|
||||
{
|
||||
xe_a1p.Counter = 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* update internal state */
|
||||
xe_a1p.State = data;
|
||||
}
|
31
source/input_hw/xe_a1p.h
Normal file
@ -0,0 +1,31 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* XE-A1P analog controller support
|
||||
*
|
||||
* Copyright Eke-Eke (2007-2011)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _XE_A1PH_
|
||||
#define _XE_A1PH_
|
||||
|
||||
/* Function prototypes */
|
||||
extern void xe_a1p_reset(void);
|
||||
extern unsigned char xe_a1p_read(void);
|
||||
extern void xe_a1p_write(unsigned char data, unsigned char mask);
|
||||
|
||||
#endif
|
450
source/io_ctrl.c
Normal file
@ -0,0 +1,450 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* I/O controller (MD & MS compatibility modes)
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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 "shared.h"
|
||||
#include "gamepad.h"
|
||||
#include "lightgun.h"
|
||||
#include "mouse.h"
|
||||
#include "activator.h"
|
||||
#include "xe_a1p.h"
|
||||
#include "teamplayer.h"
|
||||
#include "paddle.h"
|
||||
#include "sportspad.h"
|
||||
|
||||
uint8 io_reg[0x10];
|
||||
|
||||
uint8 region_code = REGION_USA;
|
||||
|
||||
static struct port_t
|
||||
{
|
||||
void (*data_w)(unsigned char data, unsigned char mask);
|
||||
unsigned char (*data_r)(void);
|
||||
} port[3];
|
||||
|
||||
static void dummy_write(unsigned char data, unsigned char mask)
|
||||
{
|
||||
}
|
||||
|
||||
static unsigned char dummy_read(void)
|
||||
{
|
||||
return 0x7F;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* I/O chip functions *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
void io_init(void)
|
||||
{
|
||||
/* Initialize connected peripherals */
|
||||
input_init();
|
||||
|
||||
/* Initialize IO Ports handlers & connected peripherals */
|
||||
switch (input.system[0])
|
||||
{
|
||||
case SYSTEM_MS_GAMEPAD:
|
||||
{
|
||||
port[0].data_w = dummy_write;
|
||||
port[0].data_r = gamepad_1_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MD_GAMEPAD:
|
||||
{
|
||||
port[0].data_w = gamepad_1_write;
|
||||
port[0].data_r = gamepad_1_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MOUSE:
|
||||
{
|
||||
port[0].data_w = mouse_write;
|
||||
port[0].data_r = mouse_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_ACTIVATOR:
|
||||
{
|
||||
port[0].data_w = activator_1_write;
|
||||
port[0].data_r = activator_1_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_XE_A1P:
|
||||
{
|
||||
port[0].data_w = xe_a1p_write;
|
||||
port[0].data_r = xe_a1p_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
{
|
||||
port[0].data_w = wayplay_1_write;
|
||||
port[0].data_r = wayplay_1_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
{
|
||||
port[0].data_w = teamplayer_1_write;
|
||||
port[0].data_r = teamplayer_1_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_LIGHTPHASER:
|
||||
{
|
||||
port[0].data_w = dummy_write;
|
||||
port[0].data_r = phaser_1_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_PADDLE:
|
||||
{
|
||||
port[0].data_w = paddle_1_write;
|
||||
port[0].data_r = paddle_1_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_SPORTSPAD:
|
||||
{
|
||||
port[0].data_w = sportspad_1_write;
|
||||
port[0].data_r = sportspad_1_read;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
port[0].data_w = dummy_write;
|
||||
port[0].data_r = dummy_read;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (input.system[1])
|
||||
{
|
||||
case SYSTEM_MS_GAMEPAD:
|
||||
{
|
||||
port[1].data_w = dummy_write;
|
||||
port[1].data_r = gamepad_2_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MD_GAMEPAD:
|
||||
{
|
||||
port[1].data_w = gamepad_2_write;
|
||||
port[1].data_r = gamepad_2_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MOUSE:
|
||||
{
|
||||
port[1].data_w = mouse_write;
|
||||
port[1].data_r = mouse_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_ACTIVATOR:
|
||||
{
|
||||
port[1].data_w = activator_2_write;
|
||||
port[1].data_r = activator_2_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_MENACER:
|
||||
{
|
||||
port[1].data_w = dummy_write;
|
||||
port[1].data_r = menacer_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_JUSTIFIER:
|
||||
{
|
||||
port[1].data_w = justifier_write;
|
||||
port[1].data_r = justifier_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
{
|
||||
port[1].data_w = wayplay_2_write;
|
||||
port[1].data_r = wayplay_2_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
{
|
||||
port[1].data_w = teamplayer_2_write;
|
||||
port[1].data_r = teamplayer_2_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_LIGHTPHASER:
|
||||
{
|
||||
port[1].data_w = dummy_write;
|
||||
port[1].data_r = phaser_2_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_PADDLE:
|
||||
{
|
||||
port[1].data_w = paddle_2_write;
|
||||
port[1].data_r = paddle_2_read;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSTEM_SPORTSPAD:
|
||||
{
|
||||
port[1].data_w = sportspad_2_write;
|
||||
port[1].data_r = sportspad_2_read;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
port[1].data_w = dummy_write;
|
||||
port[1].data_r = dummy_read;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* External Port (unconnected) */
|
||||
port[2].data_w = dummy_write;
|
||||
port[2].data_r = dummy_read;
|
||||
}
|
||||
|
||||
|
||||
void io_reset(void)
|
||||
{
|
||||
/* Reset I/O registers */
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
/* SMS compatibility mode control register */
|
||||
io_reg[0x00] = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Genesis mode registers */
|
||||
io_reg[0x00] = region_code | 0x20 | (config.tmss & 1);
|
||||
io_reg[0x01] = 0x00;
|
||||
io_reg[0x02] = 0x00;
|
||||
io_reg[0x03] = 0x00;
|
||||
io_reg[0x04] = 0x00;
|
||||
io_reg[0x05] = 0x00;
|
||||
io_reg[0x06] = 0x00;
|
||||
io_reg[0x07] = 0xFF;
|
||||
io_reg[0x08] = 0x00;
|
||||
io_reg[0x09] = 0x00;
|
||||
io_reg[0x0A] = 0xFF;
|
||||
io_reg[0x0B] = 0x00;
|
||||
io_reg[0x0C] = 0x00;
|
||||
io_reg[0x0D] = 0xFB;
|
||||
io_reg[0x0E] = 0x00;
|
||||
io_reg[0x0F] = 0x00;
|
||||
}
|
||||
|
||||
/* Reset connected peripherals */
|
||||
input_reset();
|
||||
}
|
||||
|
||||
void io_68k_write(unsigned int offset, unsigned int data)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x01: /* Port A Data */
|
||||
case 0x02: /* Port B Data */
|
||||
case 0x03: /* Port C Data */
|
||||
{
|
||||
io_reg[offset] = data;
|
||||
port[offset-1].data_w(data, io_reg[offset + 3]);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x04: /* Port A Ctrl */
|
||||
case 0x05: /* Port B Ctrl */
|
||||
case 0x06: /* Port C Ctrl */
|
||||
{
|
||||
if (data != io_reg[offset])
|
||||
{
|
||||
io_reg[offset] = data;
|
||||
port[offset-4].data_w(io_reg[offset-3], data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x07: /* Port A TxData */
|
||||
case 0x0A: /* Port B TxData */
|
||||
case 0x0D: /* Port C TxData */
|
||||
{
|
||||
io_reg[offset] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x09: /* Port A S-Ctrl */
|
||||
case 0x0C: /* Port B S-Ctrl */
|
||||
case 0x0F: /* Port C S-Ctrl */
|
||||
{
|
||||
io_reg[offset] = data & 0xF8;
|
||||
return;
|
||||
}
|
||||
|
||||
default: /* Read-only ports */
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int io_68k_read(unsigned int offset)
|
||||
{
|
||||
switch(offset)
|
||||
{
|
||||
case 0x01: /* Port A Data */
|
||||
case 0x02: /* Port B Data */
|
||||
case 0x03: /* Port C Data */
|
||||
{
|
||||
unsigned int mask = 0x80 | io_reg[offset + 3];
|
||||
unsigned int data = port[offset-1].data_r();
|
||||
return (io_reg[offset] & mask) | (data & ~mask);
|
||||
}
|
||||
|
||||
default: /* return register value */
|
||||
{
|
||||
return io_reg[offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void io_z80_write(unsigned int data)
|
||||
{
|
||||
/* pins can't be configured as output on japanese models */
|
||||
if (region_code & REGION_USA)
|
||||
{
|
||||
/*
|
||||
Bit Function
|
||||
--------------
|
||||
D7 : Port B TH pin output level (1=high, 0=low)
|
||||
D6 : Port B TR pin output level (1=high, 0=low)
|
||||
D5 : Port A TH pin output level (1=high, 0=low)
|
||||
D4 : Port A TR pin output level (1=high, 0=low)
|
||||
D3 : Port B TH pin direction (1=input, 0=output)
|
||||
D2 : Port B TR pin direction (1=input, 0=output)
|
||||
D1 : Port A TH pin direction (1=input, 0=output)
|
||||
D0 : Port A TR pin direction (1=input, 0=output)
|
||||
*/
|
||||
|
||||
/* Send TR/TH state to connected peripherals */
|
||||
port[0].data_w((data << 1) & 0x60, (~io_reg[0] << 5) & 0x60);
|
||||
port[1].data_w((data >> 1) & 0x60, (~io_reg[0] << 3) & 0x60);
|
||||
|
||||
|
||||
/* Check for TH low-to-high transitions on both ports */
|
||||
if ((!(io_reg[0] & 0x80) && (data & 0x80)) ||
|
||||
(!(io_reg[0] & 0x20) && (data & 0x20)))
|
||||
{
|
||||
/* Latch new HVC */
|
||||
hvc_latch = hctab[(mcycles_z80 + Z80_CYCLE_OFFSET) % MCYCLES_PER_LINE] | 0x10000;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* outputs return fixed value */
|
||||
data &= 0x0F;
|
||||
}
|
||||
|
||||
/* Update control register */
|
||||
io_reg[0] = data;
|
||||
}
|
||||
|
||||
unsigned int io_z80_read(unsigned int offset)
|
||||
{
|
||||
/* Read port A & port B input data */
|
||||
unsigned int data = (port[0].data_r()) | (port[1].data_r() << 8);
|
||||
|
||||
/* Read control register value */
|
||||
unsigned int ctrl = io_reg[0];
|
||||
|
||||
/* I/O ports */
|
||||
if (offset)
|
||||
{
|
||||
/*
|
||||
Bit Function
|
||||
--------------
|
||||
D7 : Port B TH pin input
|
||||
D6 : Port A TH pin input
|
||||
D5 : Unused (0 on Mega Drive, 1 otherwise)
|
||||
D4 : RESET button (always 1 on Mega Drive)
|
||||
D3 : Port B TR pin input
|
||||
D2 : Port B TL pin input
|
||||
D1 : Port B Right pin input
|
||||
D0 : Port B Left pin input
|
||||
*/
|
||||
data = ((data >> 10) & 0x0F) | (data & 0x40) | ((data >> 7) & 0x80) | 0x10;
|
||||
|
||||
/* Adjust port B TH state if configured as output */
|
||||
if (!(ctrl & 0x08))
|
||||
{
|
||||
data &= ~0x80;
|
||||
data |= (ctrl & 0x80);
|
||||
}
|
||||
|
||||
/* Adjust port A TH state if configured as output */
|
||||
if (!(ctrl & 0x02))
|
||||
{
|
||||
data &= ~0x40;
|
||||
data |= ((ctrl & 0x20) << 1);
|
||||
}
|
||||
|
||||
/* Adjust port B TR state if configured as output */
|
||||
if (!(ctrl & 0x04))
|
||||
{
|
||||
data &= ~0x08;
|
||||
data |= ((ctrl & 0x40) >> 3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Bit Function
|
||||
--------------
|
||||
D7 : Port B Down pin input
|
||||
D6 : Port B Up pin input
|
||||
D5 : Port A TR pin input
|
||||
D4 : Port A TL pin input
|
||||
D3 : Port A Right pin input
|
||||
D2 : Port A Left pin input
|
||||
D1 : Port A Down pin input
|
||||
D0 : Port A Up pin input
|
||||
*/
|
||||
data = (data & 0x3F) | ((data >> 2) & 0xC0);
|
||||
|
||||
/* Adjust port A TR state if configured as output */
|
||||
if (!(ctrl & 0x01))
|
||||
{
|
||||
data &= ~0x20;
|
||||
data |= ((ctrl & 0x10) << 1);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
45
source/io_ctrl.h
Normal file
@ -0,0 +1,45 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* I/O controller (MD & MS compatibility modes)
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _GEN_IO_H_
|
||||
#define _GEN_IO_H_
|
||||
|
||||
#define REGION_JAPAN_NTSC 0x00
|
||||
#define REGION_JAPAN_PAL 0x40
|
||||
#define REGION_USA 0x80
|
||||
#define REGION_EUROPE 0xC0
|
||||
|
||||
/* Global variables */
|
||||
extern uint8 io_reg[0x10];
|
||||
extern uint8 region_code;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void io_init(void);
|
||||
extern void io_reset(void);
|
||||
extern void io_68k_write(unsigned int offset, unsigned int data);
|
||||
extern unsigned int io_68k_read(unsigned int offset);
|
||||
extern void io_z80_write(unsigned int data);
|
||||
extern unsigned int io_z80_read(unsigned int offset);
|
||||
|
||||
#endif /* _IO_H_ */
|
||||
|
425
source/loadrom.c
@ -60,7 +60,6 @@
|
||||
#define MAXCOMPANY 64
|
||||
#define MAXPERIPHERALS 14
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char companyid[6];
|
||||
@ -84,7 +83,8 @@ char rom_filename[256];
|
||||
* Based on the document provided at
|
||||
* http://www.zophar.net/tech/files/Genesis_ROM_Format.txt
|
||||
**************************************************************************/
|
||||
static COMPANYINFO companyinfo[MAXCOMPANY] = {
|
||||
static const COMPANYINFO companyinfo[MAXCOMPANY] =
|
||||
{
|
||||
{"ACLD", "Ballistic"},
|
||||
{"RSI", "Razorsoft"},
|
||||
{"SEGA", "SEGA"},
|
||||
@ -157,7 +157,8 @@ static COMPANYINFO companyinfo[MAXCOMPANY] = {
|
||||
* Based on the document provided at
|
||||
* http://www.zophar.net/tech/files/Genesis_ROM_Format.txt
|
||||
***************************************************************************/
|
||||
static PERIPHERALINFO peripheralinfo[MAXPERIPHERALS] = {
|
||||
static const PERIPHERALINFO peripheralinfo[MAXPERIPHERALS] =
|
||||
{
|
||||
{"J", "3B Joypad"},
|
||||
{"6", "6B Joypad"},
|
||||
{"K", "Keyboard"},
|
||||
@ -175,11 +176,10 @@ static PERIPHERALINFO peripheralinfo[MAXPERIPHERALS] = {
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* GetRealChecksum
|
||||
*
|
||||
* Compute ROM checksum.
|
||||
* Compute ROM real checksum.
|
||||
***************************************************************************/
|
||||
static uint16 GetRealChecksum (uint8 *rom, int length)
|
||||
static uint16 getchecksum(uint8 *rom, int length)
|
||||
{
|
||||
int i;
|
||||
uint16 checksum = 0;
|
||||
@ -193,60 +193,157 @@ static uint16 GetRealChecksum (uint8 *rom, int length)
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* getrominfo
|
||||
*
|
||||
* Pass a pointer to the ROM base address.
|
||||
***************************************************************************/
|
||||
static void getrominfo (char *romheader)
|
||||
static void getrominfo(char *romheader)
|
||||
{
|
||||
int i,j;
|
||||
uint16 offset = 0;
|
||||
|
||||
/* Clear ROM info structure */
|
||||
memset (&rominfo, 0, sizeof (ROMINFO));
|
||||
|
||||
memcpy (&rominfo.consoletype, romheader + ROMCONSOLE, 16);
|
||||
memcpy (&rominfo.copyright, romheader + ROMCOPYRIGHT, 16);
|
||||
|
||||
rominfo.domestic[0] = romheader[ROMDOMESTIC];
|
||||
j=1;
|
||||
for (i=1; i<48; i++)
|
||||
/* Look for Master System ROM header */
|
||||
if (!memcmp (&cart.rom[0x1ff0], "TMR SEGA", 8))
|
||||
{
|
||||
if ((rominfo.domestic[j-1] != 32) || (romheader[ROMDOMESTIC + i] != 32))
|
||||
offset = 0x1ff0;
|
||||
}
|
||||
else if (!memcmp (&cart.rom[0x3ff0], "TMR SEGA", 8))
|
||||
{
|
||||
offset = 0x3ff0;
|
||||
}
|
||||
else if (!memcmp (&cart.rom[0x7ff0], "TMR SEGA", 8))
|
||||
{
|
||||
offset = 0x7ff0;
|
||||
}
|
||||
|
||||
/* If found, assume this is a SMS game */
|
||||
if (offset)
|
||||
{
|
||||
/* force SMS compatibilty mode */
|
||||
system_hw = SYSTEM_PBC;
|
||||
|
||||
/* checksum */
|
||||
rominfo.checksum = cart.rom[offset + 0x0a] | (cart.rom[offset + 0x0b] << 8);
|
||||
|
||||
/* product code & version */
|
||||
sprintf(&rominfo.product[0], "%02d", cart.rom[offset + 0x0e] >> 4);
|
||||
sprintf(&rominfo.product[2], "%02x", cart.rom[offset + 0x0d]);
|
||||
sprintf(&rominfo.product[4], "%02x", cart.rom[offset + 0x0c]);
|
||||
sprintf(&rominfo.product[6], "-%d", cart.rom[offset + 0x0e] & 0x0F);
|
||||
|
||||
/* region code */
|
||||
switch (cart.rom[offset + 0x0f] >> 4)
|
||||
{
|
||||
rominfo.domestic[j] = romheader[ROMDOMESTIC + i];
|
||||
j++;
|
||||
case 3:
|
||||
strcpy(rominfo.country,"SMS Japan");
|
||||
break;
|
||||
case 4:
|
||||
strcpy(rominfo.country,"SMS Export");
|
||||
break;
|
||||
case 5:
|
||||
strcpy(rominfo.country,"GG Japan");
|
||||
break;
|
||||
case 6:
|
||||
strcpy(rominfo.country,"GG Export");
|
||||
break;
|
||||
case 7:
|
||||
strcpy(rominfo.country,"GG International");
|
||||
break;
|
||||
default:
|
||||
sprintf(rominfo.country,"Unknown (%d)", cart.rom[offset + 0x0f] >> 4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ROM size */
|
||||
rominfo.romstart = 0;
|
||||
switch (cart.rom[offset + 0x0f] & 0x0F)
|
||||
{
|
||||
case 0x00:
|
||||
rominfo.romend = 0x3FFFF;
|
||||
break;
|
||||
case 0x01:
|
||||
rominfo.romend = 0x7FFFF;
|
||||
break;
|
||||
case 0x02:
|
||||
rominfo.romend = 0xFFFFF;
|
||||
break;
|
||||
case 0x0a:
|
||||
rominfo.romend = 0x1FFF;
|
||||
break;
|
||||
case 0x0b:
|
||||
rominfo.romend = 0x3FFF;
|
||||
break;
|
||||
case 0x0c:
|
||||
rominfo.romend = 0x7FFF;
|
||||
break;
|
||||
case 0x0d:
|
||||
rominfo.romend = 0xBFFF;
|
||||
break;
|
||||
case 0x0e:
|
||||
rominfo.romend = 0xFFFF;
|
||||
break;
|
||||
case 0x0f:
|
||||
rominfo.romend = 0x1FFFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rominfo.domestic[j] = 0;
|
||||
|
||||
rominfo.international[0] = romheader[ROMWORLD];
|
||||
j=1;
|
||||
for (i=1; i<48; i++)
|
||||
else
|
||||
{
|
||||
if ((rominfo.international[j-1] != 32) || (romheader[ROMWORLD + i] != 32))
|
||||
/* Some SMS games don't have any header */
|
||||
if (system_hw == SYSTEM_PBC) return;
|
||||
|
||||
/* Genesis ROM header support */
|
||||
memcpy (&rominfo.consoletype, romheader + ROMCONSOLE, 16);
|
||||
memcpy (&rominfo.copyright, romheader + ROMCOPYRIGHT, 16);
|
||||
|
||||
/* Domestic (japanese) name */
|
||||
rominfo.domestic[0] = romheader[ROMDOMESTIC];
|
||||
int i, j = 1;
|
||||
for (i=1; i<48; i++)
|
||||
{
|
||||
rominfo.international[j] = romheader[ROMWORLD + i];
|
||||
j++;
|
||||
if ((rominfo.domestic[j-1] != 32) || (romheader[ROMDOMESTIC + i] != 32))
|
||||
{
|
||||
rominfo.domestic[j] = romheader[ROMDOMESTIC + i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
rominfo.international[j] = 0;
|
||||
rominfo.domestic[j] = 0;
|
||||
|
||||
memcpy (&rominfo.ROMType, romheader + ROMTYPE, 2);
|
||||
memcpy (&rominfo.product, romheader + ROMPRODUCT, 12);
|
||||
memcpy (&rominfo.checksum, romheader + ROMCHECKSUM, 2);
|
||||
memcpy (&rominfo.romstart, romheader + ROMROMSTART, 4);
|
||||
memcpy (&rominfo.romend, romheader + ROMROMEND, 4);
|
||||
memcpy (&rominfo.country, romheader + ROMCOUNTRY, 16);
|
||||
/* International name */
|
||||
rominfo.international[0] = romheader[ROMWORLD];
|
||||
j=1;
|
||||
for (i=1; i<48; i++)
|
||||
{
|
||||
if ((rominfo.international[j-1] != 32) || (romheader[ROMWORLD + i] != 32))
|
||||
{
|
||||
rominfo.international[j] = romheader[ROMWORLD + i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
rominfo.international[j] = 0;
|
||||
|
||||
/* ROM informations */
|
||||
memcpy (&rominfo.ROMType, romheader + ROMTYPE, 2);
|
||||
memcpy (&rominfo.product, romheader + ROMPRODUCT, 12);
|
||||
memcpy (&rominfo.checksum, romheader + ROMCHECKSUM, 2);
|
||||
memcpy (&rominfo.romstart, romheader + ROMROMSTART, 4);
|
||||
memcpy (&rominfo.romend, romheader + ROMROMEND, 4);
|
||||
memcpy (&rominfo.country, romheader + ROMCOUNTRY, 16);
|
||||
|
||||
/* Checksums */
|
||||
#ifdef LSB_FIRST
|
||||
rominfo.checksum = (rominfo.checksum >> 8) | ((rominfo.checksum & 0xff) << 8);
|
||||
rominfo.checksum = (rominfo.checksum >> 8) | ((rominfo.checksum & 0xff) << 8);
|
||||
#endif
|
||||
rominfo.realchecksum = GetRealChecksum (((uint8 *) cart.rom) + 0x200, cart.romsize - 0x200);
|
||||
rominfo.realchecksum = getchecksum(((uint8 *) cart.rom) + 0x200, cart.romsize - 0x200);
|
||||
|
||||
rominfo.peripherals = 0;
|
||||
for (i = 0; i < 14; i++)
|
||||
for (j=0; j < 14; j++)
|
||||
if (romheader[ROMIOSUPPORT+i] == peripheralinfo[j].pID[0])
|
||||
rominfo.peripherals |= (1 << j);
|
||||
/* Supported peripherals */
|
||||
rominfo.peripherals = 0;
|
||||
for (i = 0; i < 14; i++)
|
||||
for (j=0; j < 14; j++)
|
||||
if (romheader[ROMIOSUPPORT+i] == peripheralinfo[j].pID[0])
|
||||
rominfo.peripherals |= (1 << j);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
@ -273,61 +370,71 @@ static void deinterleave_block(uint8 * src)
|
||||
***************************************************************************/
|
||||
int load_rom(char *filename)
|
||||
{
|
||||
int i, size, offset = 0;
|
||||
int i, size;
|
||||
|
||||
#ifdef NGC
|
||||
size = cart.romsize;
|
||||
sprintf(rom_filename,"%s",filename);
|
||||
rom_filename[strlen(rom_filename) - 4] = 0;
|
||||
#else
|
||||
uint8 *ptr;
|
||||
ptr = load_archive(filename, &size);
|
||||
if(!ptr) return (0);
|
||||
memcpy(cart.rom, ptr + offset, size);
|
||||
memcpy(cart.rom, ptr, size);
|
||||
free(ptr);
|
||||
#endif
|
||||
|
||||
/* detect interleaved format (.SMD) */
|
||||
/* Minimal ROM size */
|
||||
if (size < 0x4000)
|
||||
{
|
||||
memset(cart.rom + size, 0xFF, 0x4000 - size);
|
||||
size = 0x4000;
|
||||
}
|
||||
|
||||
/* Get file extension */
|
||||
if (!strnicmp(".sms", &filename[strlen(filename) - 4], 4))
|
||||
{
|
||||
/* Force SMS compatibility mode */
|
||||
system_hw = SYSTEM_PBC;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Assume Genesis mode */
|
||||
system_hw = SYSTEM_GENESIS;
|
||||
}
|
||||
|
||||
/* Take care of 512 byte header, if present */
|
||||
if (strncmp((char *)(cart.rom + 0x100),"SEGA", 4) && ((size / 512) & 1))
|
||||
{
|
||||
size -= 512;
|
||||
offset += 512;
|
||||
for (i = 0; i < (size / 0x4000); i += 1)
|
||||
deinterleave_block (cart.rom + offset + (i * 0x4000));
|
||||
memcpy(cart.rom, cart.rom + offset, size);
|
||||
memcpy (cart.rom, cart.rom + 512, size);
|
||||
|
||||
/* interleaved ROM format (.smd) */
|
||||
if (system_hw != SYSTEM_PBC)
|
||||
{
|
||||
for (i = 0; i < (size / 0x4000); i++)
|
||||
{
|
||||
deinterleave_block (cart.rom + (i * 0x4000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* max. 10 MBytes supported */
|
||||
if (size > MAXROMSIZE) size = MAXROMSIZE;
|
||||
cart.romsize = size;
|
||||
|
||||
|
||||
/* clear unused ROM space */
|
||||
memset(cart.rom + size, 0xff, MAXROMSIZE - size);
|
||||
|
||||
/* get infos from ROM header */
|
||||
getrominfo((char *)cart.rom);
|
||||
|
||||
/* get specific input devices */
|
||||
input_autodetect();
|
||||
|
||||
/* get default region */
|
||||
/* detect console region */
|
||||
region_autodetect();
|
||||
|
||||
/* Genesis ROM specific */
|
||||
if (system_hw != SYSTEM_PBC)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
/* Byteswap ROM */
|
||||
uint8 temp;
|
||||
for(i = 0; i < size; i += 2)
|
||||
{
|
||||
temp = cart.rom[i];
|
||||
cart.rom[i] = cart.rom[i+1];
|
||||
cart.rom[i+1] = temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* byteswapped RADICA dumps (from Haze) */
|
||||
if (((strstr(rominfo.product,"-K0101") != NULL) && (rominfo.checksum == 0xf424)) ||
|
||||
((strstr(rominfo.product,"-K0109") != NULL) && (rominfo.checksum == 0x4f10)))
|
||||
{
|
||||
/* Byteswap ROM */
|
||||
uint8 temp;
|
||||
for(i = 0; i < size; i += 2)
|
||||
{
|
||||
@ -335,15 +442,27 @@ int load_rom(char *filename)
|
||||
cart.rom[i] = cart.rom[i+1];
|
||||
cart.rom[i+1] = temp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* console hardware */
|
||||
if (strstr(rominfo.consoletype, "SEGA PICO") != NULL)
|
||||
system_hw = SYSTEM_PICO;
|
||||
else if (strstr(rominfo.consoletype, "SEGA MEGADRIVE") != NULL)
|
||||
system_hw = SYSTEM_MEGADRIVE;
|
||||
else
|
||||
system_hw = SYSTEM_GENESIS;
|
||||
/* byteswapped RADICA dumps (from Haze) */
|
||||
if (((strstr(rominfo.product,"-K0101") != NULL) && (rominfo.checksum == 0xf424)) ||
|
||||
((strstr(rominfo.product,"-K0109") != NULL) && (rominfo.checksum == 0x4f10)))
|
||||
{
|
||||
uint8 temp;
|
||||
for(i = 0; i < size; i += 2)
|
||||
{
|
||||
temp = cart.rom[i];
|
||||
cart.rom[i] = cart.rom[i+1];
|
||||
cart.rom[i+1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/* PICO hardware */
|
||||
if (strstr(rominfo.consoletype, "SEGA PICO") != NULL)
|
||||
{
|
||||
system_hw = SYSTEM_PICO;
|
||||
}
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
@ -356,83 +475,79 @@ int load_rom(char *filename)
|
||||
****************************************************************************/
|
||||
void region_autodetect(void)
|
||||
{
|
||||
/* country codes used to differentiate region */
|
||||
/* 0001 = japan ntsc (1) */
|
||||
/* 0010 = japan pal (2) */
|
||||
/* 0100 = usa (4) */
|
||||
/* 1000 = europe (8) */
|
||||
|
||||
int country = 0;
|
||||
int i = 0;
|
||||
char c;
|
||||
|
||||
/* reading header to find the country */
|
||||
if (!strnicmp(rominfo.country, "eur", 3)) country |= 8;
|
||||
else if (!strnicmp(rominfo.country, "usa", 3)) country |= 4;
|
||||
else if (!strnicmp(rominfo.country, "jap", 3)) country |= 1;
|
||||
|
||||
else for(i = 0; i < 4; i++)
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
c = toupper((int)rominfo.country[i]);
|
||||
if (c == 'U') country |= 4;
|
||||
else if (c == 'J') country |= 1;
|
||||
else if (c == 'E') country |= 8;
|
||||
else if (c == 'K') country |= 1;
|
||||
else if (c < 16) country |= c;
|
||||
else if ((c >= '0') && (c <= '9')) country |= c - '0';
|
||||
else if ((c >= 'A') && (c <= 'F')) country |= c - 'A' + 10;
|
||||
region_code = sms_cart_region_detect();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* country codes used to differentiate region */
|
||||
/* 0001 = japan ntsc (1) */
|
||||
/* 0010 = japan pal (2) */
|
||||
/* 0100 = usa (4) */
|
||||
/* 1000 = europe (8) */
|
||||
int country = 0;
|
||||
int i = 0;
|
||||
char c;
|
||||
|
||||
/* from Gens */
|
||||
if (!strnicmp(rominfo.country, "eur", 3)) country |= 8;
|
||||
else if (!strnicmp(rominfo.country, "usa", 3)) country |= 4;
|
||||
else if (!strnicmp(rominfo.country, "jap", 3)) country |= 1;
|
||||
else
|
||||
{
|
||||
/* look for each characters */
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
c = toupper((int)rominfo.country[i]);
|
||||
|
||||
if (c == 'U') country |= 4;
|
||||
else if (c == 'J') country |= 1;
|
||||
else if (c == 'E') country |= 8;
|
||||
else if (c == 'K') country |= 1;
|
||||
else if (c < 16) country |= c;
|
||||
else if ((c >= '0') && (c <= '9')) country |= c - '0';
|
||||
else if ((c >= 'A') && (c <= 'F')) country |= c - 'A' + 10;
|
||||
}
|
||||
}
|
||||
|
||||
/* set default console region (USA > JAPAN > EUROPE) */
|
||||
if (country & 4) region_code = REGION_USA;
|
||||
else if (country & 1) region_code = REGION_JAPAN_NTSC;
|
||||
else if (country & 8) region_code = REGION_EUROPE;
|
||||
else if (country & 2) region_code = REGION_JAPAN_PAL;
|
||||
else region_code = REGION_USA;
|
||||
|
||||
/* some games need specific REGION setting */
|
||||
if (((strstr(rominfo.product,"T-45033") != NULL) && (rominfo.checksum == 0x0F81)) || /* Alisia Dragon (Europe) */
|
||||
(strstr(rominfo.product,"T-69046-50") != NULL) || /* Back to the Future III (Europe) */
|
||||
(strstr(rominfo.product,"T-120106-00") != NULL) || /* Brian Lara Cricket (Europe) */
|
||||
(strstr(rominfo.product,"T-70096 -00") != NULL)) /* Muhammad Ali Heavyweight Boxing (Europe) */
|
||||
{
|
||||
/* need PAL settings */
|
||||
region_code = REGION_EUROPE;
|
||||
}
|
||||
|
||||
if ((rominfo.realchecksum == 0x532e) && (strstr(rominfo.product,"1011-00") != NULL))
|
||||
{
|
||||
/* On Dal Jang Goon (Korea) needs JAPAN region code */
|
||||
region_code = REGION_JAPAN_NTSC;
|
||||
}
|
||||
}
|
||||
|
||||
/* automatic detection */
|
||||
/* setting region */
|
||||
/* this is used by IO register */
|
||||
if (country & 4) region_code = REGION_USA;
|
||||
else if (country & 1) region_code = REGION_JAPAN_NTSC;
|
||||
else if (country & 8) region_code = REGION_EUROPE;
|
||||
else if (country & 2) region_code = REGION_JAPAN_PAL;
|
||||
else region_code = REGION_USA;
|
||||
/* forced console region */
|
||||
if (config.region_detect == 1) region_code = REGION_USA;
|
||||
else if (config.region_detect == 2) region_code = REGION_EUROPE;
|
||||
else if (config.region_detect == 3) region_code = REGION_JAPAN_NTSC;
|
||||
else if (config.region_detect == 4) region_code = REGION_JAPAN_PAL;
|
||||
|
||||
/* some games need specific REGION setting */
|
||||
if (((strstr(rominfo.product,"T-45033") != NULL) && (rominfo.checksum == 0x0F81)) || /* Alisia Dragon (PAL) */
|
||||
(strstr(rominfo.product,"T-69046-50") != NULL) || /* Back to the Future III (PAL) */
|
||||
(strstr(rominfo.product,"T-120106-00") != NULL) || /* Brian Lara Cricket (PAL) */
|
||||
(strstr(rominfo.product,"T-70096 -00") != NULL)) /* Muhammad Ali Heavyweight Boxing (PAL) */
|
||||
{
|
||||
/* need PAL settings */
|
||||
region_code = REGION_EUROPE;
|
||||
}
|
||||
else if ((rominfo.realchecksum == 0x532e) && (strstr(rominfo.product,"1011-00") != NULL))
|
||||
{
|
||||
/* On Dal Jang Goon (Korea) needs JAP region code */
|
||||
region_code = REGION_JAPAN_NTSC;
|
||||
}
|
||||
|
||||
/* Force region setting */
|
||||
if (config.region_detect == 1)
|
||||
region_code = REGION_USA;
|
||||
else if (config.region_detect == 2)
|
||||
region_code = REGION_EUROPE;
|
||||
else if (config.region_detect == 3)
|
||||
region_code = REGION_JAPAN_NTSC;
|
||||
else if (config.region_detect == 4)
|
||||
region_code = REGION_JAPAN_PAL;
|
||||
|
||||
/* Set VDP default mode */
|
||||
switch (region_code)
|
||||
{
|
||||
case REGION_EUROPE:
|
||||
case REGION_JAPAN_PAL:
|
||||
vdp_pal = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
vdp_pal = 0;
|
||||
break;
|
||||
}
|
||||
/* PAL/NTSC timings */
|
||||
vdp_pal = (region_code & REGION_JAPAN_PAL) >> 6;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* get_company
|
||||
* get_company (Softdev - 2006)
|
||||
*
|
||||
* Try to determine which company made this rom
|
||||
*
|
||||
@ -446,8 +561,10 @@ char *get_company(void)
|
||||
int i;
|
||||
char company[10];
|
||||
|
||||
for (i = 3; i < 8; i++)
|
||||
for (i = 3; i < 8; i++)
|
||||
{
|
||||
company[i - 3] = rominfo.copyright[i];
|
||||
}
|
||||
company[5] = 0;
|
||||
|
||||
/** OK, first look for a hyphen
|
||||
@ -466,19 +583,19 @@ char *get_company(void)
|
||||
company[i] = 0;
|
||||
|
||||
if (strlen (company) == 0)
|
||||
return companyinfo[MAXCOMPANY - 1].company;
|
||||
return (char *)companyinfo[MAXCOMPANY - 1].company;
|
||||
|
||||
for (i = 0; i < MAXCOMPANY - 1; i++)
|
||||
{
|
||||
if (!(strncmp (company, companyinfo[i].companyid, strlen (company))))
|
||||
return companyinfo[i].company;
|
||||
return (char *)companyinfo[i].company;
|
||||
}
|
||||
|
||||
return companyinfo[MAXCOMPANY - 1].company;
|
||||
return (char *)companyinfo[MAXCOMPANY - 1].company;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* get_peripheral
|
||||
* get_peripheral (Softdev - 2006)
|
||||
*
|
||||
* Return peripheral name based on header code
|
||||
*
|
||||
@ -486,7 +603,7 @@ char *get_company(void)
|
||||
char *get_peripheral(int index)
|
||||
{
|
||||
if (index < MAXPERIPHERALS)
|
||||
return peripheralinfo[index].pName;
|
||||
return companyinfo[MAXCOMPANY - 1].company;
|
||||
return (char *)peripheralinfo[index].pName;
|
||||
return (char *)companyinfo[MAXCOMPANY - 1].company;
|
||||
}
|
||||
|
||||
|
@ -381,7 +381,7 @@ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_
|
||||
unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type);
|
||||
|
||||
/*** Not really required, but makes for clean compile under DevkitPPC ***/
|
||||
extern int vdp_int_ack_callback(int int_level);
|
||||
extern int vdp_68k_irq_ack(int int_level);
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================== MAME STUFF ============================== */
|
||||
|
@ -82,7 +82,7 @@
|
||||
* auto-clear when the interrupt is serviced.
|
||||
*/
|
||||
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER
|
||||
#define M68K_INT_ACK_CALLBACK(A) vdp_int_ack_callback(A)
|
||||
#define M68K_INT_ACK_CALLBACK(A) vdp_68k_irq_ack(A)
|
||||
|
||||
|
||||
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters
|
||||
|
@ -846,7 +846,7 @@ void m68k_set_irq(unsigned int int_level)
|
||||
extern uint16 v_counter;
|
||||
extern void error(char *format, ...);
|
||||
#endif
|
||||
extern uint8 irq_status;
|
||||
extern uint8 m68k_irq_state;
|
||||
|
||||
void m68k_run (unsigned int cycles)
|
||||
{
|
||||
@ -856,13 +856,13 @@ void m68k_run (unsigned int cycles)
|
||||
while (mcycles_68k < cycles)
|
||||
{
|
||||
/* check IRQ triggering */
|
||||
if (irq_status & 0x10)
|
||||
if (m68k_irq_state & 0x10)
|
||||
{
|
||||
irq_status &= ~0x10;
|
||||
CPU_INT_LEVEL = (irq_status & 6) << 8;
|
||||
m68k_irq_state &= ~0x10;
|
||||
CPU_INT_LEVEL = (m68k_irq_state & 6) << 8;
|
||||
|
||||
/* IRQ was triggered during previous instruction */
|
||||
if (irq_status & 0x20)
|
||||
if (m68k_irq_state & 0x20)
|
||||
{
|
||||
/* one instruction latency */
|
||||
REG_IR = m68ki_read_imm_16();
|
||||
|
@ -1451,9 +1451,13 @@ INLINE void m68ki_jump(uint new_pc)
|
||||
|
||||
INLINE void m68ki_jump_vector(uint vector)
|
||||
{
|
||||
#if M68K_EMULATE_040 || M68K_EMULATE_020 || M68K_EMULATE_EC020 || M68K_EMULATE_010
|
||||
REG_PC = (vector<<2) + REG_VBR;
|
||||
REG_PC = m68ki_read_data_32(REG_PC);
|
||||
#else
|
||||
REG_PC = m68ki_read_data_32(vector<<2);
|
||||
m68ki_pc_changed(REG_PC);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1993,10 +1997,6 @@ INLINE void m68ki_exception_address_error(void)
|
||||
/* Service an interrupt request and start exception processing */
|
||||
INLINE void m68ki_exception_interrupt(uint int_level)
|
||||
{
|
||||
uint vector;
|
||||
uint sr;
|
||||
uint new_pc;
|
||||
|
||||
#if M68K_EMULATE_ADDRESS_ERROR == OPT_ON
|
||||
if(CPU_TYPE_IS_000(CPU_TYPE))
|
||||
{
|
||||
@ -2012,30 +2012,23 @@ INLINE void m68ki_exception_interrupt(uint int_level)
|
||||
return;
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
vector = m68ki_int_ack(int_level);
|
||||
m68ki_int_ack(int_level);
|
||||
|
||||
/* Get the interrupt vector */
|
||||
if(vector == M68K_INT_ACK_AUTOVECTOR)
|
||||
/* Use the autovectors. This is the most commonly used implementation */
|
||||
vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level;
|
||||
else if(vector == M68K_INT_ACK_SPURIOUS)
|
||||
/* Called if no devices respond to the interrupt acknowledge */
|
||||
vector = EXCEPTION_SPURIOUS_INTERRUPT;
|
||||
else if(vector > 255)
|
||||
{
|
||||
M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n",
|
||||
m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector));
|
||||
return;
|
||||
}
|
||||
/* Always use the autovectors. */
|
||||
uint vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level;
|
||||
|
||||
/* Start exception processing */
|
||||
sr = m68ki_init_exception();
|
||||
uint sr = m68ki_init_exception();
|
||||
|
||||
/* Set the interrupt mask to the level of the one being serviced */
|
||||
FLAG_INT_MASK = int_level<<8;
|
||||
|
||||
/* Get the new PC */
|
||||
new_pc = m68ki_read_data_32((vector<<2) + REG_VBR);
|
||||
#if M68K_EMULATE_040 || M68K_EMULATE_020 || M68K_EMULATE_EC020 || M68K_EMULATE_010
|
||||
uint new_pc = m68ki_read_data_32((vector<<2) + REG_VBR);
|
||||
#else
|
||||
uint new_pc = m68ki_read_data_32(vector<<2);
|
||||
#endif
|
||||
|
||||
/* If vector is uninitialized, call the uninitialized interrupt vector */
|
||||
if(new_pc == 0)
|
||||
@ -2043,6 +2036,7 @@ INLINE void m68ki_exception_interrupt(uint int_level)
|
||||
|
||||
/* Generate a stack frame */
|
||||
m68ki_stack_frame_0000(REG_PC, sr, vector);
|
||||
#if M68K_EMULATE_040 || M68K_EMULATE_020 || M68K_EMULATE_EC020 || M68K_EMULATE_010
|
||||
if(FLAG_M && CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
|
||||
{
|
||||
/* Create throwaway frame */
|
||||
@ -2050,6 +2044,7 @@ INLINE void m68ki_exception_interrupt(uint int_level)
|
||||
sr |= 0x2000; /* Same as SR in master stack frame except S is forced high */
|
||||
m68ki_stack_frame_0001(REG_PC, sr, vector);
|
||||
}
|
||||
#endif
|
||||
|
||||
m68ki_jump(new_pc);
|
||||
|
||||
|
114
source/mem68k.c
@ -1,6 +1,6 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* 68k bus address decoding
|
||||
* 68k bus controller
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
@ -124,7 +124,7 @@ unsigned int eeprom_read_byte(unsigned int address)
|
||||
|
||||
unsigned int eeprom_read_word(unsigned int address)
|
||||
{
|
||||
if (address == (eeprom.type.sda_out_adr & 0xfffffe))
|
||||
if (address == (eeprom.type.sda_out_adr & 0xFFFFFE))
|
||||
{
|
||||
return eeprom_read(1);
|
||||
}
|
||||
@ -143,7 +143,7 @@ void eeprom_write_byte(unsigned int address, unsigned int data)
|
||||
|
||||
void eeprom_write_word(unsigned int address, unsigned int data)
|
||||
{
|
||||
if ((address == (eeprom.type.sda_in_adr & 0xfffffe)) || (address == (eeprom.type.scl_adr & 0xfffffe)))
|
||||
if ((address == (eeprom.type.sda_in_adr & 0xFFFFFE)) || (address == (eeprom.type.scl_adr & 0xFFFFFE)))
|
||||
{
|
||||
eeprom_write(address, data, 1);
|
||||
return;
|
||||
@ -166,17 +166,17 @@ unsigned int z80_read_byte(unsigned int address)
|
||||
|
||||
case 3: /* Misc */
|
||||
{
|
||||
if ((address & 0xff00) == 0x7f00)
|
||||
if ((address & 0xFF00) == 0x7F00)
|
||||
{
|
||||
/* VDP (through 68k bus) */
|
||||
return m68k_lockup_r_8(address);
|
||||
}
|
||||
return (m68k_read_bus_8(address) | 0xff);
|
||||
return (m68k_read_bus_8(address) | 0xFF);
|
||||
}
|
||||
|
||||
default: /* ZRAM */
|
||||
{
|
||||
return zram[address & 0x1fff];
|
||||
return zram[address & 0x1FFF];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,7 +199,7 @@ void z80_write_byte(unsigned int address, unsigned int data)
|
||||
|
||||
case 3:
|
||||
{
|
||||
switch ((address >> 8) & 0x7f)
|
||||
switch ((address >> 8) & 0x7F)
|
||||
{
|
||||
case 0x60: /* Bank register */
|
||||
{
|
||||
@ -207,7 +207,7 @@ void z80_write_byte(unsigned int address, unsigned int data)
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x7f: /* VDP */
|
||||
case 0x7F: /* VDP */
|
||||
{
|
||||
m68k_lockup_w_8(address, data);
|
||||
return;
|
||||
@ -223,7 +223,7 @@ void z80_write_byte(unsigned int address, unsigned int data)
|
||||
|
||||
default: /* ZRAM */
|
||||
{
|
||||
zram[address & 0x1fff] = data;
|
||||
zram[address & 0x1FFF] = data;
|
||||
mcycles_68k += 8; /* ZRAM access latency (fixes Pacman 2: New Adventures) */
|
||||
return;
|
||||
}
|
||||
@ -241,13 +241,13 @@ void z80_write_word(unsigned int address, unsigned int data)
|
||||
/*--------------------------------------------------------------------------*/
|
||||
unsigned int ctrl_io_read_byte(unsigned int address)
|
||||
{
|
||||
switch ((address >> 8) & 0xff)
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x00: /* I/O chip */
|
||||
{
|
||||
if (!(address & 0xe0))
|
||||
if (!(address & 0xE0))
|
||||
{
|
||||
return io_read((address >> 1) & 0x0f);
|
||||
return io_68k_read((address >> 1) & 0x0F);
|
||||
}
|
||||
return m68k_read_bus_8(address);
|
||||
}
|
||||
@ -256,7 +256,7 @@ unsigned int ctrl_io_read_byte(unsigned int address)
|
||||
{
|
||||
if (!(address & 1))
|
||||
{
|
||||
unsigned int data = m68k_read_pcrelative_8(REG_PC) & 0xfe;
|
||||
unsigned int data = m68k_read_pcrelative_8(REG_PC) & 0xFE;
|
||||
if (zstate == 3)
|
||||
{
|
||||
return data;
|
||||
@ -273,7 +273,7 @@ unsigned int ctrl_io_read_byte(unsigned int address)
|
||||
unsigned int data = cart.hw.time_r(address);
|
||||
if (address & 1)
|
||||
{
|
||||
return (data & 0xff);
|
||||
return (data & 0xFF);
|
||||
}
|
||||
return (data >> 8);
|
||||
}
|
||||
@ -284,7 +284,7 @@ unsigned int ctrl_io_read_byte(unsigned int address)
|
||||
{
|
||||
if (address & 1)
|
||||
{
|
||||
unsigned int data = m68k_read_pcrelative_8(REG_PC) & 0xfe;
|
||||
unsigned int data = m68k_read_pcrelative_8(REG_PC) & 0xFE;
|
||||
return (gen_bankswitch_r() | data);
|
||||
}
|
||||
return m68k_read_bus_8(address);
|
||||
@ -309,13 +309,13 @@ unsigned int ctrl_io_read_byte(unsigned int address)
|
||||
|
||||
unsigned int ctrl_io_read_word(unsigned int address)
|
||||
{
|
||||
switch ((address >> 8) & 0xff)
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x00: /* I/O chip */
|
||||
{
|
||||
if (!(address & 0xe0))
|
||||
if (!(address & 0xE0))
|
||||
{
|
||||
unsigned int data = io_read((address >> 1) & 0x0f);
|
||||
unsigned int data = io_68k_read((address >> 1) & 0x0F);
|
||||
return (data << 8 | data);
|
||||
}
|
||||
return m68k_read_bus_16(address);
|
||||
@ -323,7 +323,7 @@ unsigned int ctrl_io_read_word(unsigned int address)
|
||||
|
||||
case 0x11: /* BUSACK */
|
||||
{
|
||||
unsigned int data = m68k_read_pcrelative_16(REG_PC) & 0xfeff;
|
||||
unsigned int data = m68k_read_pcrelative_16(REG_PC) & 0xFEFF;
|
||||
if (zstate == 3)
|
||||
{
|
||||
return data;
|
||||
@ -342,12 +342,12 @@ unsigned int ctrl_io_read_word(unsigned int address)
|
||||
|
||||
case 0x50: /* SVP */
|
||||
{
|
||||
if ((address & 0xfd) == 0)
|
||||
if ((address & 0xFD) == 0)
|
||||
{
|
||||
return svp->ssp1601.gr[SSP_XST].h;
|
||||
}
|
||||
|
||||
if ((address & 0xff) == 4)
|
||||
if ((address & 0xFF) == 4)
|
||||
{
|
||||
unsigned int data = svp->ssp1601.gr[SSP_PM0].h;
|
||||
svp->ssp1601.gr[SSP_PM0].h &= ~1;
|
||||
@ -376,14 +376,14 @@ unsigned int ctrl_io_read_word(unsigned int address)
|
||||
|
||||
void ctrl_io_write_byte(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch ((address >> 8) & 0xff)
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x00: /* I/O chip */
|
||||
{
|
||||
if ((address & 0xe1) == 0x01)
|
||||
if ((address & 0xE1) == 0x01)
|
||||
{
|
||||
/* get /LWR only */
|
||||
io_write((address >> 1) & 0x0f, data);
|
||||
io_68k_write((address >> 1) & 0x0F, data);
|
||||
return;
|
||||
}
|
||||
m68k_unused_8_w(address, data);
|
||||
@ -449,13 +449,13 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data)
|
||||
|
||||
void ctrl_io_write_word(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch ((address >> 8) & 0xff)
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x00: /* I/O chip */
|
||||
{
|
||||
if (!(address & 0xe0))
|
||||
if (!(address & 0xE0))
|
||||
{
|
||||
io_write((address >> 1) & 0x0f, data & 0xff);
|
||||
io_68k_write((address >> 1) & 0x0F, data & 0xFF);
|
||||
return;
|
||||
}
|
||||
m68k_unused_16_w(address, data);
|
||||
@ -493,7 +493,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
|
||||
|
||||
case 0x50: /* SVP REGISTERS */
|
||||
{
|
||||
if (!(address & 0xfd))
|
||||
if (!(address & 0xFD))
|
||||
{
|
||||
svp->ssp1601.gr[SSP_XST].h = data;
|
||||
svp->ssp1601.gr[SSP_PM0].h |= 2;
|
||||
@ -527,44 +527,44 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
|
||||
/*--------------------------------------------------------------------------*/
|
||||
unsigned int vdp_read_byte(unsigned int address)
|
||||
{
|
||||
switch (address & 0xfd)
|
||||
switch (address & 0xFD)
|
||||
{
|
||||
case 0x00: /* DATA */
|
||||
{
|
||||
return (vdp_data_r() >> 8);
|
||||
return (vdp_68k_data_r() >> 8);
|
||||
}
|
||||
|
||||
case 0x01: /* DATA */
|
||||
{
|
||||
return (vdp_data_r() & 0xff);
|
||||
return (vdp_68k_data_r() & 0xFF);
|
||||
}
|
||||
|
||||
case 0x04: /* CTRL */
|
||||
{
|
||||
return (((vdp_ctrl_r(mcycles_68k) >> 8) & 3) | (m68k_read_pcrelative_8(REG_PC) & 0xfc));
|
||||
return (((vdp_ctrl_r(mcycles_68k) >> 8) & 3) | (m68k_read_pcrelative_8(REG_PC) & 0xFC));
|
||||
}
|
||||
|
||||
case 0x05: /* CTRL */
|
||||
{
|
||||
return (vdp_ctrl_r(mcycles_68k) & 0xff);
|
||||
return (vdp_ctrl_r(mcycles_68k) & 0xFF);
|
||||
}
|
||||
|
||||
case 0x08: /* HVC */
|
||||
case 0x0c:
|
||||
case 0x0C:
|
||||
{
|
||||
return (vdp_hvc_r(mcycles_68k) >> 8);
|
||||
}
|
||||
|
||||
case 0x09: /* HVC */
|
||||
case 0x0d:
|
||||
case 0x0D:
|
||||
{
|
||||
return (vdp_hvc_r(mcycles_68k) & 0xff);
|
||||
return (vdp_hvc_r(mcycles_68k) & 0xFF);
|
||||
}
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x19:
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
{
|
||||
return m68k_read_bus_8(address);
|
||||
}
|
||||
@ -578,11 +578,11 @@ unsigned int vdp_read_byte(unsigned int address)
|
||||
|
||||
unsigned int vdp_read_word(unsigned int address)
|
||||
{
|
||||
switch (address & 0xfc)
|
||||
switch (address & 0xFC)
|
||||
{
|
||||
case 0x00: /* DATA */
|
||||
{
|
||||
return vdp_data_r();
|
||||
return vdp_68k_data_r();
|
||||
}
|
||||
|
||||
case 0x04: /* CTRL */
|
||||
@ -591,13 +591,13 @@ unsigned int vdp_read_word(unsigned int address)
|
||||
}
|
||||
|
||||
case 0x08: /* HVC */
|
||||
case 0x0c:
|
||||
case 0x0C:
|
||||
{
|
||||
return vdp_hvc_r(mcycles_68k);
|
||||
}
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x1c:
|
||||
case 0x1C:
|
||||
{
|
||||
return m68k_read_bus_16(address);
|
||||
}
|
||||
@ -611,17 +611,17 @@ unsigned int vdp_read_word(unsigned int address)
|
||||
|
||||
void vdp_write_byte(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch (address & 0xfc)
|
||||
switch (address & 0xFC)
|
||||
{
|
||||
case 0x00: /* Data port */
|
||||
{
|
||||
vdp_data_w(data << 8 | data);
|
||||
vdp_68k_data_w(data << 8 | data);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x04: /* Control port */
|
||||
{
|
||||
vdp_ctrl_w(data << 8 | data);
|
||||
vdp_68k_ctrl_w(data << 8 | data);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -643,7 +643,7 @@ void vdp_write_byte(unsigned int address, unsigned int data)
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x1c: /* TEST register */
|
||||
case 0x1C: /* TEST register */
|
||||
{
|
||||
vdp_test_w(data << 8 | data);
|
||||
return;
|
||||
@ -659,24 +659,24 @@ void vdp_write_byte(unsigned int address, unsigned int data)
|
||||
|
||||
void vdp_write_word(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch (address & 0xfc)
|
||||
switch (address & 0xFC)
|
||||
{
|
||||
case 0x00: /* DATA */
|
||||
{
|
||||
vdp_data_w(data);
|
||||
vdp_68k_data_w(data);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x04: /* CTRL */
|
||||
{
|
||||
vdp_ctrl_w(data);
|
||||
vdp_68k_ctrl_w(data);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x10: /* PSG */
|
||||
case 0x14:
|
||||
{
|
||||
psg_write(mcycles_68k, data & 0xff);
|
||||
psg_write(mcycles_68k, data & 0xFF);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -686,7 +686,7 @@ void vdp_write_word(unsigned int address, unsigned int data)
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x1c: /* Test register */
|
||||
case 0x1C: /* Test register */
|
||||
{
|
||||
vdp_test_w(data);
|
||||
return;
|
||||
@ -706,7 +706,7 @@ void vdp_write_word(unsigned int address, unsigned int data)
|
||||
unsigned int pico_read_byte(unsigned int address)
|
||||
{
|
||||
/* PICO */
|
||||
switch (address & 0xff)
|
||||
switch (address & 0xFF)
|
||||
{
|
||||
case 0x01: /* VERSION register */
|
||||
{
|
||||
@ -715,7 +715,7 @@ unsigned int pico_read_byte(unsigned int address)
|
||||
|
||||
case 0x03: /* IO register */
|
||||
{
|
||||
unsigned int retval = 0xff;
|
||||
unsigned int retval = 0xFF;
|
||||
if (input.pad[0] & INPUT_B) retval &= ~0x10;
|
||||
if (input.pad[0] & INPUT_A) retval &= ~0x80;
|
||||
if (input.pad[0] & INPUT_UP) retval &= ~0x01;
|
||||
@ -734,7 +734,7 @@ unsigned int pico_read_byte(unsigned int address)
|
||||
|
||||
case 0x07: /* LSB PEN X coordinate */
|
||||
{
|
||||
return (input.analog[0][0] & 0xff);
|
||||
return (input.analog[0][0] & 0xFF);
|
||||
}
|
||||
|
||||
case 0x09: /* MSB PEN Y coordinate */
|
||||
@ -742,12 +742,12 @@ unsigned int pico_read_byte(unsigned int address)
|
||||
return (input.analog[0][1] >> 8);
|
||||
}
|
||||
|
||||
case 0x0b: /* LSB PEN Y coordinate */
|
||||
case 0x0B: /* LSB PEN Y coordinate */
|
||||
{
|
||||
return (input.analog[0][1] & 0xff);
|
||||
return (input.analog[0][1] & 0xFF);
|
||||
}
|
||||
|
||||
case 0x0d: /* PAGE register (TODO) */
|
||||
case 0x0D: /* PAGE register (TODO) */
|
||||
{
|
||||
return pico_page[pico_current];
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* 68k bus arbitration
|
||||
* 68k bus controller
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
|
@ -30,9 +30,9 @@
|
||||
unsigned int zbank_unused_r(unsigned int address)
|
||||
{
|
||||
#ifdef LOGERROR
|
||||
error("Z80 bank unused read %06X\n", address);
|
||||
error("Z80 bank unused read %06X (%x)\n", address, Z80.pc.d);
|
||||
#endif
|
||||
return (address & 1) ? 0x00 : 0xff;
|
||||
return (address & 1) ? 0x00 : 0xFF;
|
||||
}
|
||||
|
||||
void zbank_unused_w(unsigned int address, unsigned int data)
|
||||
@ -45,24 +45,24 @@ void zbank_unused_w(unsigned int address, unsigned int data)
|
||||
unsigned int zbank_lockup_r(unsigned int address)
|
||||
{
|
||||
#ifdef LOGERROR
|
||||
error("Z80 bank lockup read %06X\n", address);
|
||||
error("Z80 bank lockup read %06X (%x)\n", address, Z80.pc.d);
|
||||
#endif
|
||||
if (!config.force_dtack)
|
||||
{
|
||||
mcycles_z80 = 0xffffffff;
|
||||
mcycles_z80 = 0xFFFFFFFF;
|
||||
zstate = 0;
|
||||
}
|
||||
return 0xff;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void zbank_lockup_w(unsigned int address, unsigned int data)
|
||||
{
|
||||
#ifdef LOGERROR
|
||||
error("Z80 bank lockup write %06X = %02X\n", address, data);
|
||||
error("Z80 bank lockup write %06X = %02X (%x)\n", address, data, Z80.pc.d);
|
||||
#endif
|
||||
if (!config.force_dtack)
|
||||
{
|
||||
mcycles_z80 = 0xffffffff;
|
||||
mcycles_z80 = 0xFFFFFFFF;
|
||||
zstate = 0;
|
||||
}
|
||||
}
|
||||
@ -70,13 +70,13 @@ void zbank_lockup_w(unsigned int address, unsigned int data)
|
||||
/* I/O & Control registers */
|
||||
unsigned int zbank_read_ctrl_io(unsigned int address)
|
||||
{
|
||||
switch ((address >> 8) & 0xff)
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x00: /* I/O chip */
|
||||
{
|
||||
if (!(address & 0xe0))
|
||||
if (!(address & 0xE0))
|
||||
{
|
||||
return (io_read((address >> 1) & 0x0f));
|
||||
return (io_68k_read((address >> 1) & 0x0F));
|
||||
}
|
||||
return zbank_unused_r(address);
|
||||
}
|
||||
@ -87,7 +87,7 @@ unsigned int zbank_read_ctrl_io(unsigned int address)
|
||||
{
|
||||
return zbank_unused_r(address);
|
||||
}
|
||||
return 0xff;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
case 0x30: /* TIME */
|
||||
@ -97,7 +97,7 @@ unsigned int zbank_read_ctrl_io(unsigned int address)
|
||||
unsigned int data = cart.hw.time_r(address);
|
||||
if (address & 1)
|
||||
{
|
||||
return (data & 0xff);
|
||||
return (data & 0xFF);
|
||||
}
|
||||
return (data >> 8);
|
||||
}
|
||||
@ -108,7 +108,7 @@ unsigned int zbank_read_ctrl_io(unsigned int address)
|
||||
{
|
||||
if (address & 1)
|
||||
{
|
||||
return (gen_bankswitch_r() | 0xfe);
|
||||
return (gen_bankswitch_r() | 0xFE);
|
||||
}
|
||||
return zbank_unused_r(address);
|
||||
}
|
||||
@ -132,14 +132,14 @@ unsigned int zbank_read_ctrl_io(unsigned int address)
|
||||
|
||||
void zbank_write_ctrl_io(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch ((address >> 8) & 0xff)
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x00: /* I/O chip */
|
||||
{
|
||||
/* get /LWR only */
|
||||
if ((address & 0xe1) == 0x01)
|
||||
if ((address & 0xE1) == 0x01)
|
||||
{
|
||||
io_write((address >> 1) & 0x0f, data);
|
||||
io_68k_write((address >> 1) & 0x0F, data);
|
||||
return;
|
||||
}
|
||||
zbank_unused_w(address, data);
|
||||
@ -207,44 +207,44 @@ void zbank_write_ctrl_io(unsigned int address, unsigned int data)
|
||||
/* VDP */
|
||||
unsigned int zbank_read_vdp(unsigned int address)
|
||||
{
|
||||
switch (address & 0xfd)
|
||||
switch (address & 0xFD)
|
||||
{
|
||||
case 0x00: /* DATA */
|
||||
{
|
||||
return (vdp_data_r() >> 8);
|
||||
return (vdp_68k_data_r() >> 8);
|
||||
}
|
||||
|
||||
case 0x01: /* DATA */
|
||||
{
|
||||
return (vdp_data_r() & 0xff);
|
||||
return (vdp_68k_data_r() & 0xFF);
|
||||
}
|
||||
|
||||
case 0x04: /* CTRL */
|
||||
{
|
||||
return (((vdp_ctrl_r(mcycles_z80) >> 8) & 3) | 0xfc);
|
||||
return (((vdp_ctrl_r(mcycles_z80) >> 8) & 3) | 0xFC);
|
||||
}
|
||||
|
||||
case 0x05: /* CTRL */
|
||||
{
|
||||
return (vdp_ctrl_r(mcycles_z80) & 0xff);
|
||||
return (vdp_ctrl_r(mcycles_z80) & 0xFF);
|
||||
}
|
||||
|
||||
case 0x08: /* HVC */
|
||||
case 0x0c:
|
||||
case 0x0C:
|
||||
{
|
||||
return (vdp_hvc_r(mcycles_z80) >> 8);
|
||||
}
|
||||
|
||||
case 0x09: /* HVC */
|
||||
case 0x0d:
|
||||
case 0x0D:
|
||||
{
|
||||
return (vdp_hvc_r(mcycles_z80) & 0xff);
|
||||
return (vdp_hvc_r(mcycles_z80) & 0xFF);
|
||||
}
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x19:
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
{
|
||||
return zbank_unused_r(address);
|
||||
}
|
||||
@ -258,17 +258,17 @@ unsigned int zbank_read_vdp(unsigned int address)
|
||||
|
||||
void zbank_write_vdp(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch (address & 0xfc)
|
||||
switch (address & 0xFC)
|
||||
{
|
||||
case 0x00: /* Data port */
|
||||
{
|
||||
vdp_data_w(data << 8 | data);
|
||||
vdp_68k_data_w(data << 8 | data);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x04: /* Control port */
|
||||
{
|
||||
vdp_ctrl_w(data << 8 | data);
|
||||
vdp_68k_ctrl_w(data << 8 | data);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -290,7 +290,7 @@ void zbank_write_vdp(unsigned int address, unsigned int data)
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x1c: /* TEST register */
|
||||
case 0x1C: /* TEST register */
|
||||
{
|
||||
vdp_test_w(data << 8 | data);
|
||||
return;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* 68k bus banked access from Z80
|
||||
* Z80 bank access to 68k bus
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
|
205
source/memz80.c
@ -1,9 +1,9 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Z80 bus address decoding (Genesis mode)
|
||||
* Z80 bus controller (MD & MS compatibility modes)
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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
|
||||
@ -22,104 +22,106 @@
|
||||
****************************************************************************************/
|
||||
#include "shared.h"
|
||||
|
||||
/*
|
||||
Handlers for access to unused addresses and those which make the
|
||||
machine lock up.
|
||||
*/
|
||||
static inline void z80_unused_w(unsigned int address, unsigned int data)
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Handlers for access to unused addresses and those which make the */
|
||||
/* machine lock up. */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static inline void z80_unused_w(unsigned int address, unsigned char data)
|
||||
{
|
||||
#ifdef LOGERROR
|
||||
error("Z80 unused write %04X = %02X\n", address, data);
|
||||
error("Z80 unused write %04X = %02X (%x)\n", address, data, Z80.pc.w.l);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned int z80_unused_r(unsigned int address)
|
||||
static inline unsigned char z80_unused_r(unsigned int address)
|
||||
{
|
||||
#ifdef LOGERROR
|
||||
error("Z80 unused read %04X\n", address);
|
||||
error("Z80 unused read %04X (%x)\n", address, Z80.pc.w.l);
|
||||
#endif
|
||||
return 0xff;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
static inline void z80_lockup_w(unsigned int address, unsigned int data)
|
||||
static inline void z80_lockup_w(unsigned int address, unsigned char data)
|
||||
{
|
||||
#ifdef LOGERROR
|
||||
error("Z80 lockup write %04X = %02X\n", address, data);
|
||||
error("Z80 lockup write %04X = %02X (%x)\n", address, data, Z80.pc.w.l);
|
||||
#endif
|
||||
if (!config.force_dtack)
|
||||
{
|
||||
mcycles_z80 = 0xffffffff;
|
||||
mcycles_z80 = 0xFFFFFFFF;
|
||||
zstate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int z80_lockup_r(unsigned int address)
|
||||
static inline unsigned char z80_lockup_r(unsigned int address)
|
||||
{
|
||||
#ifdef LOGERROR
|
||||
error("Z80 lockup read %04X\n", address);
|
||||
error("Z80 lockup read %04X (%x)\n", address, Z80.pc);
|
||||
#endif
|
||||
if (!config.force_dtack)
|
||||
{
|
||||
mcycles_z80 = 0xffffffff;
|
||||
mcycles_z80 = 0xFFFFFFFF;
|
||||
zstate = 0;
|
||||
}
|
||||
return 0xff;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Z80 memory handlers
|
||||
*/
|
||||
unsigned int cpu_readmem16(unsigned int address)
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Z80 Memory handlers (Genesis mode) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned char z80_md_memory_r(unsigned int address)
|
||||
{
|
||||
switch((address >> 13) & 7)
|
||||
{
|
||||
case 0: /* Work RAM */
|
||||
case 0: /* $0000-$3FFF: Z80 RAM (8K mirrored) */
|
||||
case 1:
|
||||
{
|
||||
return zram[address & 0x1fff];
|
||||
return zram[address & 0x1FFF];
|
||||
}
|
||||
|
||||
case 2: /* YM2612 */
|
||||
case 2: /* $4000-$5FFF: YM2612 */
|
||||
{
|
||||
return fm_read(mcycles_68k, address & 3);
|
||||
return fm_read(mcycles_z80, address & 3);
|
||||
}
|
||||
|
||||
case 3: /* VDP */
|
||||
case 3: /* $7F00-$7FFF: VDP */
|
||||
{
|
||||
if ((address >> 8) == 0x7f)
|
||||
if ((address >> 8) == 0x7F)
|
||||
{
|
||||
return (*zbank_memory_map[0xc0].read)(address);
|
||||
}
|
||||
return z80_unused_r(address);
|
||||
}
|
||||
|
||||
default: /* V-bus bank */
|
||||
default: /* $8000-$FFFF: 68k bank (32K) */
|
||||
{
|
||||
address = zbank | (address & 0x7fff);
|
||||
address = zbank | (address & 0x7FFF);
|
||||
unsigned int slot = address >> 16;
|
||||
if (zbank_memory_map[slot].read)
|
||||
{
|
||||
return (*zbank_memory_map[slot].read)(address);
|
||||
}
|
||||
return READ_BYTE(m68k_memory_map[slot].base, address & 0xffff);
|
||||
return READ_BYTE(m68k_memory_map[slot].base, address & 0xFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cpu_writemem16(unsigned int address, unsigned int data)
|
||||
void z80_md_memory_w(unsigned int address, unsigned char data)
|
||||
{
|
||||
switch((address >> 13) & 7)
|
||||
{
|
||||
case 0: /* Work RAM */
|
||||
case 0: /* $0000-$3FFF: Z80 RAM (8K mirrored) */
|
||||
case 1:
|
||||
{
|
||||
zram[address & 0x1fff] = data;
|
||||
zram[address & 0x1FFF] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 2: /* YM2612 */
|
||||
case 2: /* $4000-$5FFF: YM2612 */
|
||||
{
|
||||
fm_write(mcycles_z80, address & 3, data);
|
||||
return;
|
||||
@ -129,13 +131,13 @@ void cpu_writemem16(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch(address >> 8)
|
||||
{
|
||||
case 0x60:
|
||||
case 0x60: /* $6000-$60FF: Bank register */
|
||||
{
|
||||
gen_zbank_w(data & 1);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x7f:
|
||||
case 0x7F: /* $7F00-$7FFF: VDP */
|
||||
{
|
||||
(*zbank_memory_map[0xc0].write)(address, data);
|
||||
return;
|
||||
@ -149,39 +151,146 @@ void cpu_writemem16(unsigned int address, unsigned int data)
|
||||
}
|
||||
}
|
||||
|
||||
default: /* V-bus bank */
|
||||
default: /* $8000-$FFFF: 68k bank (32K) */
|
||||
{
|
||||
address = zbank | (address & 0x7fff);
|
||||
address = zbank | (address & 0x7FFF);
|
||||
unsigned int slot = address >> 16;
|
||||
if (zbank_memory_map[slot].write)
|
||||
{
|
||||
(*zbank_memory_map[slot].write)(address, data);
|
||||
return;
|
||||
}
|
||||
WRITE_BYTE(m68k_memory_map[slot].base, address & 0xffff, data);
|
||||
WRITE_BYTE(m68k_memory_map[slot].base, address & 0xFFFF, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Port handlers. Ports are unused when not in Mark III compatability mode.
|
||||
|
||||
Games that access ports anyway:
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Z80 Memory handlers (Master System mode) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned char z80_sms_memory_r(unsigned int address)
|
||||
{
|
||||
return z80_readmap[(address) >> 10][(address) & 0x03FF];
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Z80 Port handlers */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*
|
||||
Ports are unused when not in Mark III compatibility mode.
|
||||
|
||||
Genesis games that access ports anyway:
|
||||
Thunder Force IV reads port $BF in it's interrupt handler.
|
||||
*/
|
||||
|
||||
unsigned int cpu_readport16(unsigned int port)
|
||||
unsigned char z80_unused_port_r(unsigned int port)
|
||||
{
|
||||
#if LOGERROR
|
||||
error("Z80 read port %04X\n", port);
|
||||
error("Z80 unused read from port %04X (%x)\n", port, Z80.pc.w.l);
|
||||
#endif
|
||||
return 0xff;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void cpu_writeport16(unsigned int port, unsigned int data)
|
||||
void z80_unused_port_w(unsigned int port, unsigned char data)
|
||||
{
|
||||
#if LOGERROR
|
||||
error("Z80 write %02X to port %04X\n", data, port);
|
||||
error("Z80 unused write to port %04X = %02X (%x)\n", port, data, Z80.pc.w.l);
|
||||
#endif
|
||||
}
|
||||
|
||||
void z80_sms_port_w(unsigned int port, unsigned char data)
|
||||
{
|
||||
switch (port & 0xC1)
|
||||
{
|
||||
case 0x01:
|
||||
{
|
||||
io_z80_write(data);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
{
|
||||
psg_write(mcycles_z80, data);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x80:
|
||||
{
|
||||
vdp_z80_data_w(data);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x81:
|
||||
{
|
||||
vdp_z80_ctrl_w(data);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if ((port & 0xFF) == 0x3E)
|
||||
{
|
||||
/* Memory Control Register */
|
||||
/* NB: this register does not exist on MD hardware but is partially emulated to support BIOS ROM image files */
|
||||
if (data & 0x40)
|
||||
{
|
||||
/* Assume only BIOS would disable Cartridge ROM */
|
||||
if (data & 0x08)
|
||||
{
|
||||
/* BIOS ROM disabled */
|
||||
sms_cart_switch(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* BIOS ROM enabled */
|
||||
sms_cart_switch(1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
z80_unused_port_w(port, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char z80_sms_port_r(unsigned int port)
|
||||
{
|
||||
switch (port & 0xC1)
|
||||
{
|
||||
case 0x40:
|
||||
{
|
||||
return ((vdp_hvc_r(mcycles_z80) >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
case 0x41:
|
||||
{
|
||||
return (vdp_hvc_r(mcycles_z80) & 0xFF);
|
||||
}
|
||||
|
||||
case 0x80:
|
||||
{
|
||||
return vdp_z80_data_r();
|
||||
}
|
||||
|
||||
case 0x81:
|
||||
{
|
||||
return (vdp_ctrl_r(mcycles_z80) & 0xFF);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
port &= 0xFF;
|
||||
if ((port == 0xC0) || (port == 0xC1) || (port == 0xDC) || (port == 0xDD) || (port == 0xDE) || (port == 0xDF))
|
||||
{
|
||||
return io_z80_read(port & 1);
|
||||
}
|
||||
|
||||
return z80_unused_port_r(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Z80 bus arbitration (Genesis mode)
|
||||
* Z80 bus controller (MD & MS compatibility mode)
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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
|
||||
@ -23,9 +23,13 @@
|
||||
#ifndef _MEMZ80_H_
|
||||
#define _MEMZ80_H_
|
||||
|
||||
extern unsigned int cpu_readmem16(unsigned int address);
|
||||
extern void cpu_writemem16(unsigned int address, unsigned int data);
|
||||
extern unsigned int cpu_readport16(unsigned int port);
|
||||
extern void cpu_writeport16(unsigned int port, unsigned int data);
|
||||
extern unsigned char z80_md_memory_r(unsigned int address);
|
||||
extern void z80_md_memory_w(unsigned int address, unsigned char data);
|
||||
extern unsigned char z80_sms_memory_r(unsigned int address);
|
||||
|
||||
extern unsigned char z80_unused_port_r(unsigned int port);
|
||||
extern void z80_unused_port_w(unsigned int port, unsigned char data);
|
||||
extern unsigned char z80_sms_port_r(unsigned int port);
|
||||
extern void z80_sms_port_w(unsigned int port, unsigned char data);
|
||||
|
||||
#endif /* _MEMZ80_H_ */
|
||||
|
@ -1,163 +1,164 @@
|
||||
/* md_ntsc 0.1.2. http://www.slack.net/~ant/ */
|
||||
|
||||
/* Added a custom blitter to double the height md_ntsc_blit_y2 -- AamirM */
|
||||
|
||||
#include "shared.h"
|
||||
#include "md_ntsc.h"
|
||||
|
||||
/* Copyright (C) 2006 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
md_ntsc_setup_t const md_ntsc_monochrome = { 0,-1, 0, 0,.2, 0, 0,-.2,-.2,-1, 0, 0 };
|
||||
md_ntsc_setup_t const md_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
md_ntsc_setup_t const md_ntsc_svideo = { 0, 0, 0, 0, 0, 0,.2, -1, -1, 0, 0, 0 };
|
||||
md_ntsc_setup_t const md_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 0, 0 };
|
||||
|
||||
#define alignment_count 2
|
||||
#define burst_count 1
|
||||
#define rescale_in 1
|
||||
#define rescale_out 1
|
||||
|
||||
#define artifacts_mid 0.40f
|
||||
#define fringing_mid 0.30f
|
||||
#define std_decoder_hue 0
|
||||
|
||||
#define gamma_size 8
|
||||
#define artifacts_max 1.00f
|
||||
#define LUMA_CUTOFF 0.1974
|
||||
|
||||
#include "md_ntsc_impl.h"
|
||||
|
||||
/* 2 input pixels -> 4 composite samples */
|
||||
pixel_info_t const md_ntsc_pixels [alignment_count] = {
|
||||
{ PIXEL_OFFSET( -4, -9 ), { 0.1f, 0.9f, 0.9f, 0.1f } },
|
||||
{ PIXEL_OFFSET( -2, -7 ), { 0.1f, 0.9f, 0.9f, 0.1f } },
|
||||
};
|
||||
|
||||
static void correct_errors( md_ntsc_rgb_t color, md_ntsc_rgb_t* out )
|
||||
{
|
||||
unsigned i;
|
||||
for ( i = 0; i < rgb_kernel_size / 4; i++ )
|
||||
{
|
||||
md_ntsc_rgb_t error = color -
|
||||
out [i ] - out [i + 2 +16] - out [i + 4 ] - out [i + 6 +16] -
|
||||
out [i + 8] - out [(i+10)%16+16] - out [(i+12)%16] - out [(i+14)%16+16];
|
||||
CORRECT_ERROR( i + 6 + 16 );
|
||||
/*DISTRIBUTE_ERROR( 2+16, 4, 6+16 );*/
|
||||
}
|
||||
}
|
||||
|
||||
void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup )
|
||||
{
|
||||
int entry;
|
||||
init_t impl;
|
||||
if ( !setup )
|
||||
setup = &md_ntsc_composite;
|
||||
init( &impl, setup );
|
||||
|
||||
for ( entry = 0; entry < md_ntsc_palette_size; entry++ )
|
||||
{
|
||||
float bb = impl.to_float [entry >> 6 & 7];
|
||||
float gg = impl.to_float [entry >> 3 & 7];
|
||||
float rr = impl.to_float [entry & 7];
|
||||
|
||||
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
|
||||
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
||||
md_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
|
||||
|
||||
if ( setup->palette_out )
|
||||
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
|
||||
|
||||
if ( ntsc )
|
||||
{
|
||||
gen_kernel( &impl, y, i, q, ntsc->table [entry] );
|
||||
correct_errors( rgb, ntsc->table [entry] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MD_NTSC_NO_BLITTERS
|
||||
/* modified blitters to work on a line basis with genesis plus renderer*/
|
||||
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
|
||||
int in_width, int vline)
|
||||
{
|
||||
int const chunk_count = in_width / md_ntsc_in_chunk - 1;
|
||||
MD_NTSC_IN_T border = table[0];
|
||||
|
||||
MD_NTSC_BEGIN_ROW( ntsc, border,
|
||||
MD_NTSC_ADJ_IN( table[*input++] ),
|
||||
MD_NTSC_ADJ_IN( table[*input++] ),
|
||||
MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
|
||||
#ifdef NGC
|
||||
/* directly fill the RGB565 texture */
|
||||
/* one tile is 32 byte = 4x4 pixels */
|
||||
/* tiles are stored continuously in texture memory */
|
||||
in_width = MD_NTSC_OUT_WIDTH(in_width) >> 2;
|
||||
int offset = ((in_width << 5) * (vline >> 2)) + ((vline & 3) * 8);
|
||||
md_ntsc_out_t* restrict line_out = (md_ntsc_out_t*)(texturemem + offset);
|
||||
#else
|
||||
md_ntsc_out_t* restrict line_out = (md_ntsc_out_t*)(&bitmap.data[(vline * bitmap.pitch)]);
|
||||
#endif
|
||||
|
||||
int n;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 0, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 1, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
MD_NTSC_COLOR_IN( 1, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 2, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 3, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
#ifdef NGC
|
||||
line_out += 12;
|
||||
#endif
|
||||
|
||||
MD_NTSC_COLOR_IN( 2, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 4, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 5, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
MD_NTSC_COLOR_IN( 3, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 6, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 7, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
#ifdef NGC
|
||||
line_out += 12;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 0, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 1, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
MD_NTSC_COLOR_IN( 1, ntsc, border );
|
||||
MD_NTSC_RGB_OUT( 2, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 3, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
#ifdef NGC
|
||||
line_out += 12;
|
||||
#endif
|
||||
|
||||
MD_NTSC_COLOR_IN( 2, ntsc, border );
|
||||
MD_NTSC_RGB_OUT( 4, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 5, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
MD_NTSC_COLOR_IN( 3, ntsc, border );
|
||||
MD_NTSC_RGB_OUT( 6, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 7, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
}
|
||||
#endif
|
||||
/* md_ntsc 0.1.2. http://www.slack.net/~ant/ */
|
||||
|
||||
/* Added a custom blitter to double the height md_ntsc_blit_y2 -- AamirM */
|
||||
/* Added a custom blitter to work with Genesis Plus GX -- EkeEke*/
|
||||
|
||||
#include "shared.h"
|
||||
#include "md_ntsc.h"
|
||||
|
||||
/* Copyright (C) 2006 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
md_ntsc_setup_t const md_ntsc_monochrome = { 0,-1, 0, 0,.2, 0, 0,-.2,-.2,-1, 0, 0 };
|
||||
md_ntsc_setup_t const md_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
md_ntsc_setup_t const md_ntsc_svideo = { 0, 0, 0, 0, 0, 0,.2, -1, -1, 0, 0, 0 };
|
||||
md_ntsc_setup_t const md_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 0, 0 };
|
||||
|
||||
#define alignment_count 2
|
||||
#define burst_count 1
|
||||
#define rescale_in 1
|
||||
#define rescale_out 1
|
||||
|
||||
#define artifacts_mid 0.40f
|
||||
#define fringing_mid 0.30f
|
||||
#define std_decoder_hue 0
|
||||
|
||||
#define gamma_size 8
|
||||
#define artifacts_max 1.00f
|
||||
#define LUMA_CUTOFF 0.1974
|
||||
|
||||
#include "md_ntsc_impl.h"
|
||||
|
||||
/* 2 input pixels -> 4 composite samples */
|
||||
pixel_info_t const md_ntsc_pixels [alignment_count] = {
|
||||
{ PIXEL_OFFSET( -4, -9 ), { 0.1f, 0.9f, 0.9f, 0.1f } },
|
||||
{ PIXEL_OFFSET( -2, -7 ), { 0.1f, 0.9f, 0.9f, 0.1f } },
|
||||
};
|
||||
|
||||
static void correct_errors( md_ntsc_rgb_t color, md_ntsc_rgb_t* out )
|
||||
{
|
||||
unsigned i;
|
||||
for ( i = 0; i < rgb_kernel_size / 4; i++ )
|
||||
{
|
||||
md_ntsc_rgb_t error = color -
|
||||
out [i ] - out [i + 2 +16] - out [i + 4 ] - out [i + 6 +16] -
|
||||
out [i + 8] - out [(i+10)%16+16] - out [(i+12)%16] - out [(i+14)%16+16];
|
||||
CORRECT_ERROR( i + 6 + 16 );
|
||||
/*DISTRIBUTE_ERROR( 2+16, 4, 6+16 );*/
|
||||
}
|
||||
}
|
||||
|
||||
void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup )
|
||||
{
|
||||
int entry;
|
||||
init_t impl;
|
||||
if ( !setup )
|
||||
setup = &md_ntsc_composite;
|
||||
init( &impl, setup );
|
||||
|
||||
for ( entry = 0; entry < md_ntsc_palette_size; entry++ )
|
||||
{
|
||||
float bb = impl.to_float [entry >> 6 & 7];
|
||||
float gg = impl.to_float [entry >> 3 & 7];
|
||||
float rr = impl.to_float [entry & 7];
|
||||
|
||||
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
|
||||
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
||||
md_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
|
||||
|
||||
if ( setup->palette_out )
|
||||
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
|
||||
|
||||
if ( ntsc )
|
||||
{
|
||||
gen_kernel( &impl, y, i, q, ntsc->table [entry] );
|
||||
correct_errors( rgb, ntsc->table [entry] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MD_NTSC_NO_BLITTERS
|
||||
/* modified blitters to work on a line basis with genesis plus renderer*/
|
||||
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
|
||||
int in_width, int vline)
|
||||
{
|
||||
int const chunk_count = in_width / md_ntsc_in_chunk - 1;
|
||||
MD_NTSC_IN_T border = table[0];
|
||||
|
||||
MD_NTSC_BEGIN_ROW( ntsc, border,
|
||||
MD_NTSC_ADJ_IN( table[*input++] ),
|
||||
MD_NTSC_ADJ_IN( table[*input++] ),
|
||||
MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
|
||||
#ifdef NGC
|
||||
/* directly fill the RGB565 texture */
|
||||
/* one tile is 32 byte = 4x4 pixels */
|
||||
/* tiles are stored continuously in texture memory */
|
||||
in_width = MD_NTSC_OUT_WIDTH(in_width) >> 2;
|
||||
int offset = ((in_width << 5) * (vline >> 2)) + ((vline & 3) * 8);
|
||||
md_ntsc_out_t* restrict line_out = (md_ntsc_out_t*)(texturemem + offset);
|
||||
#else
|
||||
md_ntsc_out_t* restrict line_out = (md_ntsc_out_t*)(&bitmap.data[(vline * bitmap.pitch)]);
|
||||
#endif
|
||||
|
||||
int n;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 0, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 1, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
MD_NTSC_COLOR_IN( 1, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 2, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 3, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
#ifdef NGC
|
||||
line_out += 12;
|
||||
#endif
|
||||
|
||||
MD_NTSC_COLOR_IN( 2, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 4, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 5, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
MD_NTSC_COLOR_IN( 3, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 6, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 7, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
#ifdef NGC
|
||||
line_out += 12;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
|
||||
MD_NTSC_RGB_OUT( 0, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 1, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
MD_NTSC_COLOR_IN( 1, ntsc, border );
|
||||
MD_NTSC_RGB_OUT( 2, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 3, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
#ifdef NGC
|
||||
line_out += 12;
|
||||
#endif
|
||||
|
||||
MD_NTSC_COLOR_IN( 2, ntsc, border );
|
||||
MD_NTSC_RGB_OUT( 4, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 5, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
|
||||
MD_NTSC_COLOR_IN( 3, ntsc, border );
|
||||
MD_NTSC_RGB_OUT( 6, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
MD_NTSC_RGB_OUT( 7, *line_out++, MD_NTSC_OUT_DEPTH );
|
||||
}
|
||||
#endif
|
||||
|
@ -1,148 +1,148 @@
|
||||
/* Sega Genesis/Mega Drive NTSC video filter */
|
||||
|
||||
/* md_ntsc 0.1.2 */
|
||||
#ifndef MD_NTSC_H
|
||||
#define MD_NTSC_H
|
||||
|
||||
#include "md_ntsc_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
in parenthesis and should remain fairly stable in future versions. */
|
||||
typedef struct md_ntsc_setup_t
|
||||
{
|
||||
/* Basic parameters */
|
||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
||||
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
|
||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
|
||||
/* Advanced parameters */
|
||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
||||
double resolution; /* image resolution */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
||||
|
||||
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
|
||||
} md_ntsc_setup_t;
|
||||
|
||||
/* Video format presets */
|
||||
extern md_ntsc_setup_t const md_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern md_ntsc_setup_t const md_ntsc_svideo; /* color bleeding only */
|
||||
extern md_ntsc_setup_t const md_ntsc_rgb; /* crisp image */
|
||||
extern md_ntsc_setup_t const md_ntsc_monochrome;/* desaturated + artifacts */
|
||||
|
||||
enum { md_ntsc_palette_size = 512 };
|
||||
|
||||
/* Initializes and adjusts parameters. Can be called multiple times on the same
|
||||
md_ntsc_t object. Can pass NULL for either parameter. */
|
||||
typedef struct md_ntsc_t md_ntsc_t;
|
||||
void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup );
|
||||
|
||||
/* Filters one or more rows of pixels. Input pixel format is set by MD_NTSC_IN_FORMAT
|
||||
and output RGB depth is set by MD_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. */
|
||||
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
|
||||
int in_width, int vline);
|
||||
|
||||
/* Number of output pixels written by blitter for given input width. */
|
||||
#define MD_NTSC_OUT_WIDTH( in_width ) \
|
||||
(((in_width) - 3) / md_ntsc_in_chunk * md_ntsc_out_chunk + md_ntsc_out_chunk)
|
||||
|
||||
/* Number of input pixels that will fit within given output width. Might be
|
||||
rounded down slightly; use MD_NTSC_OUT_WIDTH() on result to find rounded
|
||||
value. */
|
||||
#define MD_NTSC_IN_WIDTH( out_width ) \
|
||||
((out_width) / md_ntsc_out_chunk * md_ntsc_in_chunk - md_ntsc_in_chunk + 3)
|
||||
|
||||
|
||||
/* Interface for user-defined custom blitters */
|
||||
|
||||
enum { md_ntsc_in_chunk = 4 }; /* number of input pixels read per chunk */
|
||||
enum { md_ntsc_out_chunk = 8 }; /* number of output pixels generated per chunk */
|
||||
enum { md_ntsc_black = 0 }; /* palette index for black */
|
||||
|
||||
/* Begin outputting row and start three pixels. First pixel will be cut off a bit.
|
||||
Use md_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
statement in a block (unless you're using C++). */
|
||||
#define MD_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2, pixel3 ) \
|
||||
unsigned const md_pixel0_ = (pixel0);\
|
||||
md_ntsc_rgb_t const* kernel0 = MD_NTSC_IN_FORMAT( ntsc, md_pixel0_ );\
|
||||
unsigned const md_pixel1_ = (pixel1);\
|
||||
md_ntsc_rgb_t const* kernel1 = MD_NTSC_IN_FORMAT( ntsc, md_pixel1_ );\
|
||||
unsigned const md_pixel2_ = (pixel2);\
|
||||
md_ntsc_rgb_t const* kernel2 = MD_NTSC_IN_FORMAT( ntsc, md_pixel2_ );\
|
||||
unsigned const md_pixel3_ = (pixel3);\
|
||||
md_ntsc_rgb_t const* kernel3 = MD_NTSC_IN_FORMAT( ntsc, md_pixel3_ );\
|
||||
md_ntsc_rgb_t const* kernelx0;\
|
||||
md_ntsc_rgb_t const* kernelx1 = kernel0;\
|
||||
md_ntsc_rgb_t const* kernelx2 = kernel0;\
|
||||
md_ntsc_rgb_t const* kernelx3 = kernel0
|
||||
|
||||
/* Begin input pixel */
|
||||
#define MD_NTSC_COLOR_IN( index, ntsc, color ) \
|
||||
MD_NTSC_COLOR_IN_( index, color, MD_NTSC_IN_FORMAT, ntsc )
|
||||
|
||||
/* Generate output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
|
||||
24: RRRRRRRR GGGGGGGG BBBBBBBB
|
||||
16: RRRRRGGG GGGBBBBB
|
||||
15: RRRRRGG GGGBBBBB
|
||||
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
|
||||
#define MD_NTSC_RGB_OUT( x, rgb_out, bits ) {\
|
||||
md_ntsc_rgb_t raw_ =\
|
||||
kernel0 [x+ 0] + kernel1 [(x+6)%8+16] + kernel2 [(x+4)%8 ] + kernel3 [(x+2)%8+16] +\
|
||||
kernelx0 [x+ 8] + kernelx1 [(x+6)%8+24] + kernelx2 [(x+4)%8+8] + kernelx3 [(x+2)%8+24];\
|
||||
MD_NTSC_CLAMP_( raw_, 0 );\
|
||||
MD_NTSC_RGB_OUT_( rgb_out, bits, 0 );\
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
enum { md_ntsc_entry_size = 2 * 16 };
|
||||
typedef unsigned long md_ntsc_rgb_t;
|
||||
struct md_ntsc_t {
|
||||
md_ntsc_rgb_t table [md_ntsc_palette_size] [md_ntsc_entry_size];
|
||||
};
|
||||
|
||||
#define MD_NTSC_BGR9( ntsc, n ) (ntsc)->table [n & 0x1FF]
|
||||
|
||||
#define MD_NTSC_RGB16( ntsc, n ) \
|
||||
(md_ntsc_rgb_t*) ((char*) (ntsc)->table +\
|
||||
((n << 9 & 0x3800) | (n & 0x0700) | (n >> 8 & 0x00E0)) *\
|
||||
(md_ntsc_entry_size * sizeof (md_ntsc_rgb_t) / 32))
|
||||
|
||||
/* common ntsc macros */
|
||||
#define md_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
|
||||
#define md_ntsc_clamp_mask (md_ntsc_rgb_builder * 3 / 2)
|
||||
#define md_ntsc_clamp_add (md_ntsc_rgb_builder * 0x101)
|
||||
#define MD_NTSC_CLAMP_( io, shift ) {\
|
||||
md_ntsc_rgb_t sub = (io) >> (9-(shift)) & md_ntsc_clamp_mask;\
|
||||
md_ntsc_rgb_t clamp = md_ntsc_clamp_add - sub;\
|
||||
io |= clamp;\
|
||||
clamp -= sub;\
|
||||
io &= clamp;\
|
||||
}
|
||||
|
||||
#define MD_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
|
||||
unsigned color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
|
||||
}
|
||||
|
||||
/* x is always zero except in snes_ntsc library */
|
||||
#define MD_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Sega Genesis/Mega Drive NTSC video filter */
|
||||
|
||||
/* md_ntsc 0.1.2 */
|
||||
#ifndef MD_NTSC_H
|
||||
#define MD_NTSC_H
|
||||
|
||||
#include "md_ntsc_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
in parenthesis and should remain fairly stable in future versions. */
|
||||
typedef struct md_ntsc_setup_t
|
||||
{
|
||||
/* Basic parameters */
|
||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
||||
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
|
||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
|
||||
/* Advanced parameters */
|
||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
||||
double resolution; /* image resolution */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
||||
|
||||
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
|
||||
} md_ntsc_setup_t;
|
||||
|
||||
/* Video format presets */
|
||||
extern md_ntsc_setup_t const md_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern md_ntsc_setup_t const md_ntsc_svideo; /* color bleeding only */
|
||||
extern md_ntsc_setup_t const md_ntsc_rgb; /* crisp image */
|
||||
extern md_ntsc_setup_t const md_ntsc_monochrome;/* desaturated + artifacts */
|
||||
|
||||
enum { md_ntsc_palette_size = 512 };
|
||||
|
||||
/* Initializes and adjusts parameters. Can be called multiple times on the same
|
||||
md_ntsc_t object. Can pass NULL for either parameter. */
|
||||
typedef struct md_ntsc_t md_ntsc_t;
|
||||
void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup );
|
||||
|
||||
/* Filters one or more rows of pixels. Input pixel format is set by MD_NTSC_IN_FORMAT
|
||||
and output RGB depth is set by MD_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. */
|
||||
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
|
||||
int in_width, int vline);
|
||||
|
||||
/* Number of output pixels written by blitter for given input width. */
|
||||
#define MD_NTSC_OUT_WIDTH( in_width ) \
|
||||
(((in_width) - 3) / md_ntsc_in_chunk * md_ntsc_out_chunk + md_ntsc_out_chunk)
|
||||
|
||||
/* Number of input pixels that will fit within given output width. Might be
|
||||
rounded down slightly; use MD_NTSC_OUT_WIDTH() on result to find rounded
|
||||
value. */
|
||||
#define MD_NTSC_IN_WIDTH( out_width ) \
|
||||
((out_width) / md_ntsc_out_chunk * md_ntsc_in_chunk - md_ntsc_in_chunk + 3)
|
||||
|
||||
|
||||
/* Interface for user-defined custom blitters */
|
||||
|
||||
enum { md_ntsc_in_chunk = 4 }; /* number of input pixels read per chunk */
|
||||
enum { md_ntsc_out_chunk = 8 }; /* number of output pixels generated per chunk */
|
||||
enum { md_ntsc_black = 0 }; /* palette index for black */
|
||||
|
||||
/* Begin outputting row and start three pixels. First pixel will be cut off a bit.
|
||||
Use md_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
statement in a block (unless you're using C++). */
|
||||
#define MD_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2, pixel3 ) \
|
||||
unsigned const md_pixel0_ = (pixel0);\
|
||||
md_ntsc_rgb_t const* kernel0 = MD_NTSC_IN_FORMAT( ntsc, md_pixel0_ );\
|
||||
unsigned const md_pixel1_ = (pixel1);\
|
||||
md_ntsc_rgb_t const* kernel1 = MD_NTSC_IN_FORMAT( ntsc, md_pixel1_ );\
|
||||
unsigned const md_pixel2_ = (pixel2);\
|
||||
md_ntsc_rgb_t const* kernel2 = MD_NTSC_IN_FORMAT( ntsc, md_pixel2_ );\
|
||||
unsigned const md_pixel3_ = (pixel3);\
|
||||
md_ntsc_rgb_t const* kernel3 = MD_NTSC_IN_FORMAT( ntsc, md_pixel3_ );\
|
||||
md_ntsc_rgb_t const* kernelx0;\
|
||||
md_ntsc_rgb_t const* kernelx1 = kernel0;\
|
||||
md_ntsc_rgb_t const* kernelx2 = kernel0;\
|
||||
md_ntsc_rgb_t const* kernelx3 = kernel0
|
||||
|
||||
/* Begin input pixel */
|
||||
#define MD_NTSC_COLOR_IN( index, ntsc, color ) \
|
||||
MD_NTSC_COLOR_IN_( index, color, MD_NTSC_IN_FORMAT, ntsc )
|
||||
|
||||
/* Generate output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
|
||||
24: RRRRRRRR GGGGGGGG BBBBBBBB
|
||||
16: RRRRRGGG GGGBBBBB
|
||||
15: RRRRRGG GGGBBBBB
|
||||
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
|
||||
#define MD_NTSC_RGB_OUT( x, rgb_out, bits ) {\
|
||||
md_ntsc_rgb_t raw_ =\
|
||||
kernel0 [x+ 0] + kernel1 [(x+6)%8+16] + kernel2 [(x+4)%8 ] + kernel3 [(x+2)%8+16] +\
|
||||
kernelx0 [x+ 8] + kernelx1 [(x+6)%8+24] + kernelx2 [(x+4)%8+8] + kernelx3 [(x+2)%8+24];\
|
||||
MD_NTSC_CLAMP_( raw_, 0 );\
|
||||
MD_NTSC_RGB_OUT_( rgb_out, bits, 0 );\
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
enum { md_ntsc_entry_size = 2 * 16 };
|
||||
typedef unsigned long md_ntsc_rgb_t;
|
||||
struct md_ntsc_t {
|
||||
md_ntsc_rgb_t table [md_ntsc_palette_size] [md_ntsc_entry_size];
|
||||
};
|
||||
|
||||
#define MD_NTSC_BGR9( ntsc, n ) (ntsc)->table [n & 0x1FF]
|
||||
|
||||
#define MD_NTSC_RGB16( ntsc, n ) \
|
||||
(md_ntsc_rgb_t*) ((char*) (ntsc)->table +\
|
||||
((n << 9 & 0x3800) | (n & 0x0700) | (n >> 8 & 0x00E0)) *\
|
||||
(md_ntsc_entry_size * sizeof (md_ntsc_rgb_t) / 32))
|
||||
|
||||
/* common ntsc macros */
|
||||
#define md_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
|
||||
#define md_ntsc_clamp_mask (md_ntsc_rgb_builder * 3 / 2)
|
||||
#define md_ntsc_clamp_add (md_ntsc_rgb_builder * 0x101)
|
||||
#define MD_NTSC_CLAMP_( io, shift ) {\
|
||||
md_ntsc_rgb_t sub = (io) >> (9-(shift)) & md_ntsc_clamp_mask;\
|
||||
md_ntsc_rgb_t clamp = md_ntsc_clamp_add - sub;\
|
||||
io |= clamp;\
|
||||
clamp -= sub;\
|
||||
io &= clamp;\
|
||||
}
|
||||
|
||||
#define MD_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
|
||||
unsigned color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
|
||||
}
|
||||
|
||||
/* x is always zero except in snes_ntsc library */
|
||||
#define MD_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,26 +1,26 @@
|
||||
/* Configure library by modifying this file */
|
||||
|
||||
#ifndef MD_NTSC_CONFIG_H
|
||||
#define MD_NTSC_CONFIG_H
|
||||
|
||||
/* Format of source pixels */
|
||||
#define MD_NTSC_IN_FORMAT MD_NTSC_RGB16
|
||||
/* #define MD_NTSC_IN_FORMAT MD_NTSC_BGR9 */
|
||||
|
||||
/* The following affect the built-in blitter only; a custom blitter can
|
||||
handle things however it wants. */
|
||||
|
||||
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
|
||||
#define MD_NTSC_OUT_DEPTH 16
|
||||
|
||||
/* Type of input pixel values */
|
||||
#define MD_NTSC_IN_T unsigned short
|
||||
|
||||
/* Each raw pixel input value is passed through this. You might want to mask
|
||||
the pixel index if you use the high bits as flags, etc. */
|
||||
#define MD_NTSC_ADJ_IN( in ) in
|
||||
|
||||
/* For each pixel, this is the basic operation:
|
||||
output_color = MD_NTSC_ADJ_IN( MD_NTSC_IN_T ) */
|
||||
|
||||
#endif
|
||||
/* Configure library by modifying this file */
|
||||
|
||||
#ifndef MD_NTSC_CONFIG_H
|
||||
#define MD_NTSC_CONFIG_H
|
||||
|
||||
/* Format of source pixels */
|
||||
#define MD_NTSC_IN_FORMAT MD_NTSC_RGB16
|
||||
/* #define MD_NTSC_IN_FORMAT MD_NTSC_BGR9 */
|
||||
|
||||
/* The following affect the built-in blitter only; a custom blitter can
|
||||
handle things however it wants. */
|
||||
|
||||
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
|
||||
#define MD_NTSC_OUT_DEPTH 16
|
||||
|
||||
/* Type of input pixel values */
|
||||
#define MD_NTSC_IN_T unsigned short
|
||||
|
||||
/* Each raw pixel input value is passed through this. You might want to mask
|
||||
the pixel index if you use the high bits as flags, etc. */
|
||||
#define MD_NTSC_ADJ_IN( in ) in
|
||||
|
||||
/* For each pixel, this is the basic operation:
|
||||
output_color = MD_NTSC_ADJ_IN( MD_NTSC_IN_T ) */
|
||||
|
||||
#endif
|
||||
|
@ -1,439 +1,439 @@
|
||||
/* md_ntsc 0.1.2. http://www.slack.net/~ant/ */
|
||||
|
||||
/* Common implementation of NTSC filters */
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#define DISABLE_CORRECTION 0
|
||||
|
||||
#undef PI
|
||||
#define PI 3.14159265358979323846f
|
||||
|
||||
#ifndef LUMA_CUTOFF
|
||||
#define LUMA_CUTOFF 0.20
|
||||
#endif
|
||||
#ifndef gamma_size
|
||||
#define gamma_size 1
|
||||
#endif
|
||||
#ifndef rgb_bits
|
||||
#define rgb_bits 8
|
||||
#endif
|
||||
#ifndef artifacts_max
|
||||
#define artifacts_max (artifacts_mid * 1.5f)
|
||||
#endif
|
||||
#ifndef fringing_max
|
||||
#define fringing_max (fringing_mid * 2)
|
||||
#endif
|
||||
#ifndef STD_HUE_CONDITION
|
||||
#define STD_HUE_CONDITION( setup ) 1
|
||||
#endif
|
||||
|
||||
#define ext_decoder_hue (std_decoder_hue + 15)
|
||||
#define rgb_unit (1 << rgb_bits)
|
||||
#define rgb_offset (rgb_unit * 2 + 0.5f)
|
||||
|
||||
enum { burst_size = md_ntsc_entry_size / burst_count };
|
||||
enum { kernel_half = 16 };
|
||||
enum { kernel_size = kernel_half * 2 + 1 };
|
||||
|
||||
typedef struct init_t
|
||||
{
|
||||
float to_rgb [burst_count * 6];
|
||||
float to_float [gamma_size];
|
||||
float contrast;
|
||||
float brightness;
|
||||
float artifacts;
|
||||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
} init_t;
|
||||
|
||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
||||
float t;\
|
||||
t = i * cos_b - q * sin_b;\
|
||||
q = i * sin_b + q * cos_b;\
|
||||
i = t;\
|
||||
}
|
||||
|
||||
static void init_filters( init_t* impl, md_ntsc_setup_t const* setup )
|
||||
{
|
||||
#if rescale_out > 1
|
||||
float kernels [kernel_size * 2];
|
||||
#else
|
||||
float* const kernels = impl->kernel;
|
||||
#endif
|
||||
|
||||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
|
||||
float const maxh = 32;
|
||||
float const pow_a_n = (float) pow( rolloff, maxh );
|
||||
float sum;
|
||||
int i;
|
||||
/* quadratic mapping to reduce negative (blurring) range */
|
||||
float to_angle = (float) setup->resolution + 1;
|
||||
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
|
||||
|
||||
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = i - kernel_half;
|
||||
float angle = x * to_angle;
|
||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
||||
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
|
||||
{
|
||||
float rolloff_cos_a = rolloff * (float) cos( angle );
|
||||
float num = 1 - rolloff_cos_a -
|
||||
pow_a_n * (float) cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
|
||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
float dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply blackman window and find sum */
|
||||
sum = 0;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
float x = PI * 2 / (kernel_half * 2) * i;
|
||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
}
|
||||
|
||||
/* normalize kernel */
|
||||
sum = 1.0f / sum;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
|
||||
/* generate chroma (iq) filter using gaussian kernel */
|
||||
{
|
||||
float const cutoff_factor = -0.03125f;
|
||||
float cutoff = (float) setup->bleed;
|
||||
int i;
|
||||
|
||||
if ( cutoff < 0 )
|
||||
{
|
||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= -30.0f / 0.65f;
|
||||
}
|
||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
||||
|
||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
||||
|
||||
/* normalize even and odd phases separately */
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
float sum = 0;
|
||||
int x;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
sum += kernels [x];
|
||||
|
||||
sum = 1.0f / sum;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
{
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
printf( "luma:\n" );
|
||||
for ( i = kernel_size; i < kernel_size * 2; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
printf( "chroma:\n" );
|
||||
for ( i = 0; i < kernel_size; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
*/
|
||||
|
||||
/* generate linear rescale kernels */
|
||||
#if rescale_out > 1
|
||||
{
|
||||
float weight = 1.0f;
|
||||
float* out = impl->kernel;
|
||||
int n = rescale_out;
|
||||
do
|
||||
{
|
||||
float remain = 0;
|
||||
int i;
|
||||
weight -= 1.0f / rescale_in;
|
||||
for ( i = 0; i < kernel_size * 2; i++ )
|
||||
{
|
||||
float cur = kernels [i];
|
||||
float m = cur * weight;
|
||||
*out++ = m + remain;
|
||||
remain = cur - m;
|
||||
}
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static float const default_decoder [6] =
|
||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
|
||||
static void init( init_t* impl, md_ntsc_setup_t const* setup )
|
||||
{
|
||||
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
||||
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
||||
#ifdef default_palette_contrast
|
||||
if ( !setup->palette )
|
||||
impl->contrast *= default_palette_contrast;
|
||||
#endif
|
||||
|
||||
impl->artifacts = (float) setup->artifacts;
|
||||
if ( impl->artifacts > 0 )
|
||||
impl->artifacts *= artifacts_max - artifacts_mid;
|
||||
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
|
||||
|
||||
impl->fringing = (float) setup->fringing;
|
||||
if ( impl->fringing > 0 )
|
||||
impl->fringing *= fringing_max - fringing_mid;
|
||||
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
|
||||
|
||||
init_filters( impl, setup );
|
||||
|
||||
/* generate gamma table */
|
||||
if ( gamma_size > 1 )
|
||||
{
|
||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
||||
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
|
||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
||||
int i;
|
||||
for ( i = 0; i < gamma_size; i++ )
|
||||
impl->to_float [i] =
|
||||
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
|
||||
}
|
||||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
float sat = (float) setup->saturation + 1;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
if ( !decoder )
|
||||
{
|
||||
decoder = default_decoder;
|
||||
if ( STD_HUE_CONDITION( setup ) )
|
||||
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
|
||||
}
|
||||
|
||||
{
|
||||
float s = (float) sin( hue ) * sat;
|
||||
float c = (float) cos( hue ) * sat;
|
||||
float* out = impl->to_rgb;
|
||||
int n;
|
||||
|
||||
n = burst_count;
|
||||
do
|
||||
{
|
||||
float const* in = decoder;
|
||||
int n = 3;
|
||||
do
|
||||
{
|
||||
float i = *in++;
|
||||
float q = *in++;
|
||||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
while ( --n );
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* kernel generation */
|
||||
|
||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
||||
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
|
||||
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
|
||||
)
|
||||
|
||||
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
|
||||
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
|
||||
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
|
||||
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
|
||||
)
|
||||
|
||||
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
|
||||
|
||||
enum { rgb_kernel_size = burst_size / alignment_count };
|
||||
enum { rgb_bias = rgb_unit * 2 * md_ntsc_rgb_builder };
|
||||
|
||||
typedef struct pixel_info_t
|
||||
{
|
||||
int offset;
|
||||
float negate;
|
||||
float kernel [4];
|
||||
} pixel_info_t;
|
||||
|
||||
#if rescale_in > 1
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
||||
(kernel_size * 2 * scaled))
|
||||
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#else
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
(kernel_size / 2 + (ntsc) - (scaled)),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#endif
|
||||
|
||||
extern pixel_info_t const md_ntsc_pixels [alignment_count];
|
||||
|
||||
/* Generate pixel at all burst phases and column alignments */
|
||||
static void gen_kernel( init_t* impl, float y, float i, float q, md_ntsc_rgb_t* out )
|
||||
{
|
||||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb;
|
||||
int burst_remain = burst_count;
|
||||
y -= rgb_offset;
|
||||
do
|
||||
{
|
||||
/* Encode yiq into *two* composite signals (to allow control over artifacting).
|
||||
Convolve these with kernels which: filter respective components, apply
|
||||
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
|
||||
into integer. Based on algorithm by NewRisingSun. */
|
||||
pixel_info_t const* pixel = md_ntsc_pixels;
|
||||
int alignment_remain = alignment_count;
|
||||
do
|
||||
{
|
||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
||||
float const yy = y * impl->fringing * pixel->negate;
|
||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
||||
|
||||
float const factor = impl->artifacts * pixel->negate;
|
||||
float const ii = i * factor;
|
||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
||||
|
||||
float const qq = q * factor;
|
||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
||||
|
||||
float const* k = &impl->kernel [pixel->offset];
|
||||
int n;
|
||||
++pixel;
|
||||
for ( n = rgb_kernel_size; n; --n )
|
||||
{
|
||||
float i = k[0]*ic0 + k[2]*ic2;
|
||||
float q = k[1]*qc1 + k[3]*qc3;
|
||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
||||
if ( rescale_out <= 1 )
|
||||
k--;
|
||||
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
||||
k += kernel_size * 2 - 1;
|
||||
else
|
||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
||||
{
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
|
||||
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( alignment_count > 1 && --alignment_remain );
|
||||
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
|
||||
to_rgb += 6;
|
||||
|
||||
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
|
||||
}
|
||||
while ( --burst_remain );
|
||||
}
|
||||
|
||||
static void correct_errors( md_ntsc_rgb_t color, md_ntsc_rgb_t* out );
|
||||
|
||||
#if DISABLE_CORRECTION
|
||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
||||
#else
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
md_ntsc_rgb_t fourth = (error + 2 * md_ntsc_rgb_builder) >> 2;\
|
||||
fourth &= (rgb_bias >> 1) - md_ntsc_rgb_builder;\
|
||||
fourth -= rgb_bias >> 2;\
|
||||
out [a] += fourth;\
|
||||
out [b] += fourth;\
|
||||
out [c] += fourth;\
|
||||
out [i] += error - (fourth * 3);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#define RGB_PALETTE_OUT( rgb, out_ )\
|
||||
{\
|
||||
unsigned char* out = (out_);\
|
||||
md_ntsc_rgb_t clamped = (rgb);\
|
||||
MD_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
|
||||
out [0] = (unsigned char) (clamped >> 21);\
|
||||
out [1] = (unsigned char) (clamped >> 11);\
|
||||
out [2] = (unsigned char) (clamped >> 1);\
|
||||
}
|
||||
|
||||
/* blitter related */
|
||||
|
||||
#ifndef restrict
|
||||
#if defined (__GNUC__)
|
||||
#define restrict __restrict__
|
||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
||||
#define restrict
|
||||
#else
|
||||
/* no support for restricted pointers */
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if MD_NTSC_OUT_DEPTH <= 16
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef unsigned short md_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 16-bit int type"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int md_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long md_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 32-bit int type"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* md_ntsc 0.1.2. http://www.slack.net/~ant/ */
|
||||
|
||||
/* Common implementation of NTSC filters */
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#define DISABLE_CORRECTION 0
|
||||
|
||||
#undef PI
|
||||
#define PI 3.14159265358979323846f
|
||||
|
||||
#ifndef LUMA_CUTOFF
|
||||
#define LUMA_CUTOFF 0.20
|
||||
#endif
|
||||
#ifndef gamma_size
|
||||
#define gamma_size 1
|
||||
#endif
|
||||
#ifndef rgb_bits
|
||||
#define rgb_bits 8
|
||||
#endif
|
||||
#ifndef artifacts_max
|
||||
#define artifacts_max (artifacts_mid * 1.5f)
|
||||
#endif
|
||||
#ifndef fringing_max
|
||||
#define fringing_max (fringing_mid * 2)
|
||||
#endif
|
||||
#ifndef STD_HUE_CONDITION
|
||||
#define STD_HUE_CONDITION( setup ) 1
|
||||
#endif
|
||||
|
||||
#define ext_decoder_hue (std_decoder_hue + 15)
|
||||
#define rgb_unit (1 << rgb_bits)
|
||||
#define rgb_offset (rgb_unit * 2 + 0.5f)
|
||||
|
||||
enum { burst_size = md_ntsc_entry_size / burst_count };
|
||||
enum { kernel_half = 16 };
|
||||
enum { kernel_size = kernel_half * 2 + 1 };
|
||||
|
||||
typedef struct init_t
|
||||
{
|
||||
float to_rgb [burst_count * 6];
|
||||
float to_float [gamma_size];
|
||||
float contrast;
|
||||
float brightness;
|
||||
float artifacts;
|
||||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
} init_t;
|
||||
|
||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
||||
float t;\
|
||||
t = i * cos_b - q * sin_b;\
|
||||
q = i * sin_b + q * cos_b;\
|
||||
i = t;\
|
||||
}
|
||||
|
||||
static void init_filters( init_t* impl, md_ntsc_setup_t const* setup )
|
||||
{
|
||||
#if rescale_out > 1
|
||||
float kernels [kernel_size * 2];
|
||||
#else
|
||||
float* const kernels = impl->kernel;
|
||||
#endif
|
||||
|
||||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
|
||||
float const maxh = 32;
|
||||
float const pow_a_n = (float) pow( rolloff, maxh );
|
||||
float sum;
|
||||
int i;
|
||||
/* quadratic mapping to reduce negative (blurring) range */
|
||||
float to_angle = (float) setup->resolution + 1;
|
||||
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
|
||||
|
||||
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = i - kernel_half;
|
||||
float angle = x * to_angle;
|
||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
||||
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
|
||||
{
|
||||
float rolloff_cos_a = rolloff * (float) cos( angle );
|
||||
float num = 1 - rolloff_cos_a -
|
||||
pow_a_n * (float) cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
|
||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
float dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply blackman window and find sum */
|
||||
sum = 0;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
float x = PI * 2 / (kernel_half * 2) * i;
|
||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
}
|
||||
|
||||
/* normalize kernel */
|
||||
sum = 1.0f / sum;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
|
||||
/* generate chroma (iq) filter using gaussian kernel */
|
||||
{
|
||||
float const cutoff_factor = -0.03125f;
|
||||
float cutoff = (float) setup->bleed;
|
||||
int i;
|
||||
|
||||
if ( cutoff < 0 )
|
||||
{
|
||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= -30.0f / 0.65f;
|
||||
}
|
||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
||||
|
||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
||||
|
||||
/* normalize even and odd phases separately */
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
float sum = 0;
|
||||
int x;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
sum += kernels [x];
|
||||
|
||||
sum = 1.0f / sum;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
{
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
printf( "luma:\n" );
|
||||
for ( i = kernel_size; i < kernel_size * 2; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
printf( "chroma:\n" );
|
||||
for ( i = 0; i < kernel_size; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
*/
|
||||
|
||||
/* generate linear rescale kernels */
|
||||
#if rescale_out > 1
|
||||
{
|
||||
float weight = 1.0f;
|
||||
float* out = impl->kernel;
|
||||
int n = rescale_out;
|
||||
do
|
||||
{
|
||||
float remain = 0;
|
||||
int i;
|
||||
weight -= 1.0f / rescale_in;
|
||||
for ( i = 0; i < kernel_size * 2; i++ )
|
||||
{
|
||||
float cur = kernels [i];
|
||||
float m = cur * weight;
|
||||
*out++ = m + remain;
|
||||
remain = cur - m;
|
||||
}
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static float const default_decoder [6] =
|
||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
|
||||
static void init( init_t* impl, md_ntsc_setup_t const* setup )
|
||||
{
|
||||
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
||||
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
||||
#ifdef default_palette_contrast
|
||||
if ( !setup->palette )
|
||||
impl->contrast *= default_palette_contrast;
|
||||
#endif
|
||||
|
||||
impl->artifacts = (float) setup->artifacts;
|
||||
if ( impl->artifacts > 0 )
|
||||
impl->artifacts *= artifacts_max - artifacts_mid;
|
||||
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
|
||||
|
||||
impl->fringing = (float) setup->fringing;
|
||||
if ( impl->fringing > 0 )
|
||||
impl->fringing *= fringing_max - fringing_mid;
|
||||
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
|
||||
|
||||
init_filters( impl, setup );
|
||||
|
||||
/* generate gamma table */
|
||||
if ( gamma_size > 1 )
|
||||
{
|
||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
||||
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
|
||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
||||
int i;
|
||||
for ( i = 0; i < gamma_size; i++ )
|
||||
impl->to_float [i] =
|
||||
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
|
||||
}
|
||||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
float sat = (float) setup->saturation + 1;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
if ( !decoder )
|
||||
{
|
||||
decoder = default_decoder;
|
||||
if ( STD_HUE_CONDITION( setup ) )
|
||||
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
|
||||
}
|
||||
|
||||
{
|
||||
float s = (float) sin( hue ) * sat;
|
||||
float c = (float) cos( hue ) * sat;
|
||||
float* out = impl->to_rgb;
|
||||
int n;
|
||||
|
||||
n = burst_count;
|
||||
do
|
||||
{
|
||||
float const* in = decoder;
|
||||
int n = 3;
|
||||
do
|
||||
{
|
||||
float i = *in++;
|
||||
float q = *in++;
|
||||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
while ( --n );
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* kernel generation */
|
||||
|
||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
||||
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
|
||||
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
|
||||
)
|
||||
|
||||
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
|
||||
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
|
||||
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
|
||||
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
|
||||
)
|
||||
|
||||
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
|
||||
|
||||
enum { rgb_kernel_size = burst_size / alignment_count };
|
||||
enum { rgb_bias = rgb_unit * 2 * md_ntsc_rgb_builder };
|
||||
|
||||
typedef struct pixel_info_t
|
||||
{
|
||||
int offset;
|
||||
float negate;
|
||||
float kernel [4];
|
||||
} pixel_info_t;
|
||||
|
||||
#if rescale_in > 1
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
||||
(kernel_size * 2 * scaled))
|
||||
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#else
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
(kernel_size / 2 + (ntsc) - (scaled)),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#endif
|
||||
|
||||
extern pixel_info_t const md_ntsc_pixels [alignment_count];
|
||||
|
||||
/* Generate pixel at all burst phases and column alignments */
|
||||
static void gen_kernel( init_t* impl, float y, float i, float q, md_ntsc_rgb_t* out )
|
||||
{
|
||||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb;
|
||||
int burst_remain = burst_count;
|
||||
y -= rgb_offset;
|
||||
do
|
||||
{
|
||||
/* Encode yiq into *two* composite signals (to allow control over artifacting).
|
||||
Convolve these with kernels which: filter respective components, apply
|
||||
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
|
||||
into integer. Based on algorithm by NewRisingSun. */
|
||||
pixel_info_t const* pixel = md_ntsc_pixels;
|
||||
int alignment_remain = alignment_count;
|
||||
do
|
||||
{
|
||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
||||
float const yy = y * impl->fringing * pixel->negate;
|
||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
||||
|
||||
float const factor = impl->artifacts * pixel->negate;
|
||||
float const ii = i * factor;
|
||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
||||
|
||||
float const qq = q * factor;
|
||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
||||
|
||||
float const* k = &impl->kernel [pixel->offset];
|
||||
int n;
|
||||
++pixel;
|
||||
for ( n = rgb_kernel_size; n; --n )
|
||||
{
|
||||
float i = k[0]*ic0 + k[2]*ic2;
|
||||
float q = k[1]*qc1 + k[3]*qc3;
|
||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
||||
if ( rescale_out <= 1 )
|
||||
k--;
|
||||
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
||||
k += kernel_size * 2 - 1;
|
||||
else
|
||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
||||
{
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
|
||||
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( alignment_count > 1 && --alignment_remain );
|
||||
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
|
||||
to_rgb += 6;
|
||||
|
||||
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
|
||||
}
|
||||
while ( --burst_remain );
|
||||
}
|
||||
|
||||
static void correct_errors( md_ntsc_rgb_t color, md_ntsc_rgb_t* out );
|
||||
|
||||
#if DISABLE_CORRECTION
|
||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
||||
#else
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
md_ntsc_rgb_t fourth = (error + 2 * md_ntsc_rgb_builder) >> 2;\
|
||||
fourth &= (rgb_bias >> 1) - md_ntsc_rgb_builder;\
|
||||
fourth -= rgb_bias >> 2;\
|
||||
out [a] += fourth;\
|
||||
out [b] += fourth;\
|
||||
out [c] += fourth;\
|
||||
out [i] += error - (fourth * 3);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#define RGB_PALETTE_OUT( rgb, out_ )\
|
||||
{\
|
||||
unsigned char* out = (out_);\
|
||||
md_ntsc_rgb_t clamped = (rgb);\
|
||||
MD_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
|
||||
out [0] = (unsigned char) (clamped >> 21);\
|
||||
out [1] = (unsigned char) (clamped >> 11);\
|
||||
out [2] = (unsigned char) (clamped >> 1);\
|
||||
}
|
||||
|
||||
/* blitter related */
|
||||
|
||||
#ifndef restrict
|
||||
#if defined (__GNUC__)
|
||||
#define restrict __restrict__
|
||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
||||
#define restrict
|
||||
#else
|
||||
/* no support for restricted pointers */
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if MD_NTSC_OUT_DEPTH <= 16
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef unsigned short md_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 16-bit int type"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int md_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long md_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 32-bit int type"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,195 +1,197 @@
|
||||
/* sms_ntsc 0.2.3. http://www.slack.net/~ant/ */
|
||||
|
||||
#include "shared.h"
|
||||
#include "sms_ntsc.h"
|
||||
|
||||
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
sms_ntsc_setup_t const sms_ntsc_monochrome = { 0,-1, 0, 0,.2, 0, .2,-.2,-.2,-1, 0, 0 };
|
||||
sms_ntsc_setup_t const sms_ntsc_composite = { 0, 0, 0, 0, 0, 0,.25, 0, 0, 0, 0, 0 };
|
||||
sms_ntsc_setup_t const sms_ntsc_svideo = { 0, 0, 0, 0, 0, 0,.25, -1, -1, 0, 0, 0 };
|
||||
sms_ntsc_setup_t const sms_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.70, -1, -1,-1, 0, 0 };
|
||||
|
||||
#define alignment_count 3
|
||||
#define burst_count 1
|
||||
#define rescale_in 8
|
||||
#define rescale_out 7
|
||||
|
||||
#define artifacts_mid 0.4f
|
||||
#define artifacts_max 1.2f
|
||||
#define fringing_mid 0.8f
|
||||
#define std_decoder_hue 0
|
||||
|
||||
#define gamma_size 16
|
||||
|
||||
#include "sms_ntsc_impl.h"
|
||||
|
||||
/* 3 input pixels -> 8 composite samples */
|
||||
pixel_info_t const sms_ntsc_pixels [alignment_count] = {
|
||||
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
|
||||
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
|
||||
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
|
||||
};
|
||||
|
||||
static void correct_errors( sms_ntsc_rgb_t color, sms_ntsc_rgb_t* out )
|
||||
{
|
||||
unsigned i;
|
||||
for ( i = 0; i < rgb_kernel_size / 2; i++ )
|
||||
{
|
||||
sms_ntsc_rgb_t error = color -
|
||||
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
|
||||
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
|
||||
CORRECT_ERROR( i + 3 + 28 );
|
||||
}
|
||||
}
|
||||
|
||||
void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup )
|
||||
{
|
||||
int entry;
|
||||
init_t impl;
|
||||
if ( !setup )
|
||||
setup = &sms_ntsc_composite;
|
||||
init( &impl, setup );
|
||||
|
||||
for ( entry = 0; entry < sms_ntsc_palette_size; entry++ )
|
||||
{
|
||||
float bb = impl.to_float [entry >> 8 & 0x0F];
|
||||
float gg = impl.to_float [entry >> 4 & 0x0F];
|
||||
float rr = impl.to_float [entry & 0x0F];
|
||||
|
||||
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
|
||||
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
||||
sms_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
|
||||
|
||||
if ( setup->palette_out )
|
||||
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
|
||||
|
||||
if ( ntsc )
|
||||
{
|
||||
gen_kernel( &impl, y, i, q, ntsc->table [entry] );
|
||||
correct_errors( rgb, ntsc->table [entry] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SMS_NTSC_NO_BLITTERS
|
||||
|
||||
/* modified blitters to work on a line basis with genesis plus renderer*/
|
||||
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
|
||||
int in_width, int vline)
|
||||
{
|
||||
int const chunk_count = in_width / sms_ntsc_in_chunk;
|
||||
|
||||
/* handle extra 0, 1, or 2 pixels by placing them at beginning of row */
|
||||
int const in_extra = in_width - chunk_count * sms_ntsc_in_chunk;
|
||||
unsigned const extra2 = (unsigned) -(in_extra >> 1 & 1); /* (unsigned) -1 = ~0 */
|
||||
unsigned const extra1 = (unsigned) -(in_extra & 1) | extra2;
|
||||
|
||||
SMS_NTSC_IN_T border = table[0];
|
||||
|
||||
SMS_NTSC_BEGIN_ROW( ntsc, border,
|
||||
(SMS_NTSC_ADJ_IN( table[input[0]] )) & extra2,
|
||||
(SMS_NTSC_ADJ_IN( table[input[extra2 & 1]] )) & extra1 );
|
||||
|
||||
#ifdef NGC
|
||||
/* directly fill the RGB565 texture */
|
||||
/* one tile is 32 byte = 4x4 pixels */
|
||||
/* tiles are stored continuously in texture memory */
|
||||
in_width = SMS_NTSC_OUT_WIDTH(in_width) / 4;
|
||||
int offset = ((in_width * 32) * (vline / 4)) + ((vline & 3) * 8);
|
||||
sms_ntsc_out_t* restrict line_out = (sms_ntsc_out_t*)(texturemem + offset);
|
||||
offset = 0;
|
||||
#else
|
||||
sms_ntsc_out_t* restrict line_out = (sms_ntsc_out_t*)(&bitmap.data[(vline * bitmap.pitch)]);
|
||||
#endif
|
||||
int n;
|
||||
input += in_extra;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
SMS_NTSC_COLOR_IN( 0, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 0, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 1, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 0, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 1, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
|
||||
SMS_NTSC_COLOR_IN( 1, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 2, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 3, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 2, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 3, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
|
||||
SMS_NTSC_COLOR_IN( 2, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 4, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 5, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 6, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 4, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 5, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 6, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
SMS_NTSC_COLOR_IN( 0, ntsc, border );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 0, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 1, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 0, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 1, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
|
||||
SMS_NTSC_COLOR_IN( 1, ntsc, border );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 2, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 3, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 2, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 3, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
|
||||
SMS_NTSC_COLOR_IN( 2, ntsc, border );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 4, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 5, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 6, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 4, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 5, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 6, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* sms_ntsc 0.2.3. http://www.slack.net/~ant/ */
|
||||
|
||||
#include "shared.h"
|
||||
#include "sms_ntsc.h"
|
||||
|
||||
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
/* Added a custom blitter to work with Genesis Plus GX -- EkeEke*/
|
||||
|
||||
sms_ntsc_setup_t const sms_ntsc_monochrome = { 0,-1, 0, 0,.2, 0, .2,-.2,-.2,-1, 0, 0 };
|
||||
sms_ntsc_setup_t const sms_ntsc_composite = { 0, 0, 0, 0, 0, 0,.25, 0, 0, 0, 0, 0 };
|
||||
sms_ntsc_setup_t const sms_ntsc_svideo = { 0, 0, 0, 0, 0, 0,.25, -1, -1, 0, 0, 0 };
|
||||
sms_ntsc_setup_t const sms_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.70, -1, -1,-1, 0, 0 };
|
||||
|
||||
#define alignment_count 3
|
||||
#define burst_count 1
|
||||
#define rescale_in 8
|
||||
#define rescale_out 7
|
||||
|
||||
#define artifacts_mid 0.4f
|
||||
#define artifacts_max 1.2f
|
||||
#define fringing_mid 0.8f
|
||||
#define std_decoder_hue 0
|
||||
|
||||
#define gamma_size 16
|
||||
|
||||
#include "sms_ntsc_impl.h"
|
||||
|
||||
/* 3 input pixels -> 8 composite samples */
|
||||
pixel_info_t const sms_ntsc_pixels [alignment_count] = {
|
||||
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
|
||||
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
|
||||
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
|
||||
};
|
||||
|
||||
static void correct_errors( sms_ntsc_rgb_t color, sms_ntsc_rgb_t* out )
|
||||
{
|
||||
unsigned i;
|
||||
for ( i = 0; i < rgb_kernel_size / 2; i++ )
|
||||
{
|
||||
sms_ntsc_rgb_t error = color -
|
||||
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
|
||||
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
|
||||
CORRECT_ERROR( i + 3 + 28 );
|
||||
}
|
||||
}
|
||||
|
||||
void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup )
|
||||
{
|
||||
int entry;
|
||||
init_t impl;
|
||||
if ( !setup )
|
||||
setup = &sms_ntsc_composite;
|
||||
init( &impl, setup );
|
||||
|
||||
for ( entry = 0; entry < sms_ntsc_palette_size; entry++ )
|
||||
{
|
||||
float bb = impl.to_float [entry >> 8 & 0x0F];
|
||||
float gg = impl.to_float [entry >> 4 & 0x0F];
|
||||
float rr = impl.to_float [entry & 0x0F];
|
||||
|
||||
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
|
||||
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
||||
sms_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
|
||||
|
||||
if ( setup->palette_out )
|
||||
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
|
||||
|
||||
if ( ntsc )
|
||||
{
|
||||
gen_kernel( &impl, y, i, q, ntsc->table [entry] );
|
||||
correct_errors( rgb, ntsc->table [entry] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SMS_NTSC_NO_BLITTERS
|
||||
|
||||
/* modified blitters to work on a line basis with genesis plus renderer*/
|
||||
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
|
||||
int in_width, int vline)
|
||||
{
|
||||
int const chunk_count = in_width / sms_ntsc_in_chunk;
|
||||
|
||||
/* handle extra 0, 1, or 2 pixels by placing them at beginning of row */
|
||||
int const in_extra = in_width - chunk_count * sms_ntsc_in_chunk;
|
||||
unsigned const extra2 = (unsigned) -(in_extra >> 1 & 1); /* (unsigned) -1 = ~0 */
|
||||
unsigned const extra1 = (unsigned) -(in_extra & 1) | extra2;
|
||||
|
||||
SMS_NTSC_IN_T border = table[0];
|
||||
|
||||
SMS_NTSC_BEGIN_ROW( ntsc, border,
|
||||
(SMS_NTSC_ADJ_IN( table[input[0]] )) & extra2,
|
||||
(SMS_NTSC_ADJ_IN( table[input[extra2 & 1]] )) & extra1 );
|
||||
|
||||
#ifdef NGC
|
||||
/* directly fill the RGB565 texture */
|
||||
/* one tile is 32 byte = 4x4 pixels */
|
||||
/* tiles are stored continuously in texture memory */
|
||||
in_width = SMS_NTSC_OUT_WIDTH(in_width) / 4;
|
||||
int offset = ((in_width * 32) * (vline / 4)) + ((vline & 3) * 8);
|
||||
sms_ntsc_out_t* restrict line_out = (sms_ntsc_out_t*)(texturemem + offset);
|
||||
offset = 0;
|
||||
#else
|
||||
sms_ntsc_out_t* restrict line_out = (sms_ntsc_out_t*)(&bitmap.data[(vline * bitmap.pitch)]);
|
||||
#endif
|
||||
int n;
|
||||
input += in_extra;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
SMS_NTSC_COLOR_IN( 0, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 0, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 1, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 0, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 1, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
|
||||
SMS_NTSC_COLOR_IN( 1, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 2, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 3, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 2, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 3, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
|
||||
SMS_NTSC_COLOR_IN( 2, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 4, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 5, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 6, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 4, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 5, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 6, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
SMS_NTSC_COLOR_IN( 0, ntsc, border );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 0, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 1, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 0, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 1, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
|
||||
SMS_NTSC_COLOR_IN( 1, ntsc, border );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 2, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 3, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 2, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 3, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
|
||||
SMS_NTSC_COLOR_IN( 2, ntsc, border );
|
||||
#ifdef NGC
|
||||
SMS_NTSC_RGB_OUT( 4, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 5, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
SMS_NTSC_RGB_OUT( 6, line_out[offset++], SMS_NTSC_OUT_DEPTH );
|
||||
if ((offset % 4) == 0) offset += 12;
|
||||
#else
|
||||
SMS_NTSC_RGB_OUT( 4, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 5, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
SMS_NTSC_RGB_OUT( 6, *line_out++, SMS_NTSC_OUT_DEPTH );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -1,157 +1,157 @@
|
||||
/* Sega Master System/Game Gear/TI 99/4A NTSC video filter */
|
||||
|
||||
/* sms_ntsc 0.2.3 */
|
||||
#ifndef SMS_NTSC_H
|
||||
#define SMS_NTSC_H
|
||||
|
||||
#include "sms_ntsc_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
in parenthesis and should remain fairly stable in future versions. */
|
||||
typedef struct sms_ntsc_setup_t
|
||||
{
|
||||
/* Basic parameters */
|
||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
||||
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
|
||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
|
||||
/* Advanced parameters */
|
||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
||||
double resolution; /* image resolution */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
||||
|
||||
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
|
||||
} sms_ntsc_setup_t;
|
||||
|
||||
/* Video format presets */
|
||||
extern sms_ntsc_setup_t const sms_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern sms_ntsc_setup_t const sms_ntsc_svideo; /* color bleeding only */
|
||||
extern sms_ntsc_setup_t const sms_ntsc_rgb; /* crisp image */
|
||||
extern sms_ntsc_setup_t const sms_ntsc_monochrome;/* desaturated + artifacts */
|
||||
|
||||
enum { sms_ntsc_palette_size = 4096 };
|
||||
|
||||
/* Initializes and adjusts parameters. Can be called multiple times on the same
|
||||
sms_ntsc_t object. Can pass NULL for either parameter. */
|
||||
typedef struct sms_ntsc_t sms_ntsc_t;
|
||||
void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup );
|
||||
|
||||
/* Filters one or more rows of pixels. Input pixel format is set by SMS_NTSC_IN_FORMAT
|
||||
and output RGB depth is set by SMS_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. */
|
||||
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
|
||||
int in_width, int vline);
|
||||
|
||||
/* Number of output pixels written by blitter for given input width. */
|
||||
#define SMS_NTSC_OUT_WIDTH( in_width ) \
|
||||
(((in_width) / sms_ntsc_in_chunk + 1) * sms_ntsc_out_chunk)
|
||||
|
||||
/* Number of input pixels that will fit within given output width. Might be
|
||||
rounded down slightly; use SMS_NTSC_OUT_WIDTH() on result to find rounded
|
||||
value. */
|
||||
#define SMS_NTSC_IN_WIDTH( out_width ) \
|
||||
(((out_width) / sms_ntsc_out_chunk - 1) * sms_ntsc_in_chunk + 2)
|
||||
|
||||
|
||||
/* Interface for user-defined custom blitters */
|
||||
|
||||
enum { sms_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
|
||||
enum { sms_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { sms_ntsc_black = 0 }; /* palette index for black */
|
||||
|
||||
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
|
||||
Use sms_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
statement in a block (unless you're using C++). */
|
||||
#define SMS_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2 ) \
|
||||
SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SMS_NTSC_IN_FORMAT, ntsc )
|
||||
|
||||
/* Begins input pixel */
|
||||
#define SMS_NTSC_COLOR_IN( in_index, ntsc, color_in ) \
|
||||
SMS_NTSC_COLOR_IN_( in_index, color_in, SMS_NTSC_IN_FORMAT, ntsc )
|
||||
|
||||
/* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
|
||||
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
|
||||
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
|
||||
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
|
||||
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
|
||||
#define SMS_NTSC_RGB_OUT( index, rgb_out, bits ) \
|
||||
SMS_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 )
|
||||
|
||||
|
||||
/* private */
|
||||
enum { sms_ntsc_entry_size = 3 * 14 };
|
||||
typedef unsigned long sms_ntsc_rgb_t;
|
||||
struct sms_ntsc_t {
|
||||
sms_ntsc_rgb_t table [sms_ntsc_palette_size] [sms_ntsc_entry_size];
|
||||
};
|
||||
|
||||
#define SMS_NTSC_BGR12( ntsc, n ) (ntsc)->table [n & 0xFFF]
|
||||
|
||||
#define SMS_NTSC_RGB16( ntsc, n ) \
|
||||
(sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\
|
||||
((n << 10 & 0x7800) | (n & 0x0780) | (n >> 9 & 0x0078)) *\
|
||||
(sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 8))
|
||||
|
||||
#define SMS_NTSC_RGB15( ntsc, n ) \
|
||||
(sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\
|
||||
((n << 9 & 0x3C00) | (n & 0x03C0) | (n >> 9 & 0x003C)) *\
|
||||
(sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 4))
|
||||
|
||||
/* common 3->7 ntsc macros */
|
||||
#define SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
|
||||
unsigned const sms_ntsc_pixel0_ = (pixel0);\
|
||||
sms_ntsc_rgb_t const* kernel0 = ENTRY( table, sms_ntsc_pixel0_ );\
|
||||
unsigned const sms_ntsc_pixel1_ = (pixel1);\
|
||||
sms_ntsc_rgb_t const* kernel1 = ENTRY( table, sms_ntsc_pixel1_ );\
|
||||
unsigned const sms_ntsc_pixel2_ = (pixel2);\
|
||||
sms_ntsc_rgb_t const* kernel2 = ENTRY( table, sms_ntsc_pixel2_ );\
|
||||
sms_ntsc_rgb_t const* kernelx0;\
|
||||
sms_ntsc_rgb_t const* kernelx1 = kernel0;\
|
||||
sms_ntsc_rgb_t const* kernelx2 = kernel0
|
||||
|
||||
#define SMS_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
|
||||
sms_ntsc_rgb_t raw_ =\
|
||||
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
|
||||
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
|
||||
SMS_NTSC_CLAMP_( raw_, shift );\
|
||||
SMS_NTSC_RGB_OUT_( rgb_out, bits, shift );\
|
||||
}
|
||||
|
||||
/* common ntsc macros */
|
||||
#define sms_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
|
||||
#define sms_ntsc_clamp_mask (sms_ntsc_rgb_builder * 3 / 2)
|
||||
#define sms_ntsc_clamp_add (sms_ntsc_rgb_builder * 0x101)
|
||||
#define SMS_NTSC_CLAMP_( io, shift ) {\
|
||||
sms_ntsc_rgb_t sub = (io) >> (9-(shift)) & sms_ntsc_clamp_mask;\
|
||||
sms_ntsc_rgb_t clamp = sms_ntsc_clamp_add - sub;\
|
||||
io |= clamp;\
|
||||
clamp -= sub;\
|
||||
io &= clamp;\
|
||||
}
|
||||
|
||||
#define SMS_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
|
||||
unsigned color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
|
||||
}
|
||||
|
||||
/* x is always zero except in snes_ntsc library */
|
||||
#define SMS_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Sega Master System/Game Gear/TI 99/4A NTSC video filter */
|
||||
|
||||
/* sms_ntsc 0.2.3 */
|
||||
#ifndef SMS_NTSC_H
|
||||
#define SMS_NTSC_H
|
||||
|
||||
#include "sms_ntsc_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
in parenthesis and should remain fairly stable in future versions. */
|
||||
typedef struct sms_ntsc_setup_t
|
||||
{
|
||||
/* Basic parameters */
|
||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
||||
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
|
||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
|
||||
/* Advanced parameters */
|
||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
||||
double resolution; /* image resolution */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
||||
|
||||
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
|
||||
} sms_ntsc_setup_t;
|
||||
|
||||
/* Video format presets */
|
||||
extern sms_ntsc_setup_t const sms_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern sms_ntsc_setup_t const sms_ntsc_svideo; /* color bleeding only */
|
||||
extern sms_ntsc_setup_t const sms_ntsc_rgb; /* crisp image */
|
||||
extern sms_ntsc_setup_t const sms_ntsc_monochrome;/* desaturated + artifacts */
|
||||
|
||||
enum { sms_ntsc_palette_size = 4096 };
|
||||
|
||||
/* Initializes and adjusts parameters. Can be called multiple times on the same
|
||||
sms_ntsc_t object. Can pass NULL for either parameter. */
|
||||
typedef struct sms_ntsc_t sms_ntsc_t;
|
||||
void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup );
|
||||
|
||||
/* Filters one or more rows of pixels. Input pixel format is set by SMS_NTSC_IN_FORMAT
|
||||
and output RGB depth is set by SMS_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. */
|
||||
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
|
||||
int in_width, int vline);
|
||||
|
||||
/* Number of output pixels written by blitter for given input width. */
|
||||
#define SMS_NTSC_OUT_WIDTH( in_width ) \
|
||||
(((in_width) / sms_ntsc_in_chunk + 1) * sms_ntsc_out_chunk)
|
||||
|
||||
/* Number of input pixels that will fit within given output width. Might be
|
||||
rounded down slightly; use SMS_NTSC_OUT_WIDTH() on result to find rounded
|
||||
value. */
|
||||
#define SMS_NTSC_IN_WIDTH( out_width ) \
|
||||
(((out_width) / sms_ntsc_out_chunk - 1) * sms_ntsc_in_chunk + 2)
|
||||
|
||||
|
||||
/* Interface for user-defined custom blitters */
|
||||
|
||||
enum { sms_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
|
||||
enum { sms_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { sms_ntsc_black = 0 }; /* palette index for black */
|
||||
|
||||
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
|
||||
Use sms_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
statement in a block (unless you're using C++). */
|
||||
#define SMS_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2 ) \
|
||||
SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SMS_NTSC_IN_FORMAT, ntsc )
|
||||
|
||||
/* Begins input pixel */
|
||||
#define SMS_NTSC_COLOR_IN( in_index, ntsc, color_in ) \
|
||||
SMS_NTSC_COLOR_IN_( in_index, color_in, SMS_NTSC_IN_FORMAT, ntsc )
|
||||
|
||||
/* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
|
||||
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
|
||||
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
|
||||
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
|
||||
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
|
||||
#define SMS_NTSC_RGB_OUT( index, rgb_out, bits ) \
|
||||
SMS_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 )
|
||||
|
||||
|
||||
/* private */
|
||||
enum { sms_ntsc_entry_size = 3 * 14 };
|
||||
typedef unsigned long sms_ntsc_rgb_t;
|
||||
struct sms_ntsc_t {
|
||||
sms_ntsc_rgb_t table [sms_ntsc_palette_size] [sms_ntsc_entry_size];
|
||||
};
|
||||
|
||||
#define SMS_NTSC_BGR12( ntsc, n ) (ntsc)->table [n & 0xFFF]
|
||||
|
||||
#define SMS_NTSC_RGB16( ntsc, n ) \
|
||||
(sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\
|
||||
((n << 10 & 0x7800) | (n & 0x0780) | (n >> 9 & 0x0078)) *\
|
||||
(sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 8))
|
||||
|
||||
#define SMS_NTSC_RGB15( ntsc, n ) \
|
||||
(sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\
|
||||
((n << 9 & 0x3C00) | (n & 0x03C0) | (n >> 9 & 0x003C)) *\
|
||||
(sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 4))
|
||||
|
||||
/* common 3->7 ntsc macros */
|
||||
#define SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
|
||||
unsigned const sms_ntsc_pixel0_ = (pixel0);\
|
||||
sms_ntsc_rgb_t const* kernel0 = ENTRY( table, sms_ntsc_pixel0_ );\
|
||||
unsigned const sms_ntsc_pixel1_ = (pixel1);\
|
||||
sms_ntsc_rgb_t const* kernel1 = ENTRY( table, sms_ntsc_pixel1_ );\
|
||||
unsigned const sms_ntsc_pixel2_ = (pixel2);\
|
||||
sms_ntsc_rgb_t const* kernel2 = ENTRY( table, sms_ntsc_pixel2_ );\
|
||||
sms_ntsc_rgb_t const* kernelx0;\
|
||||
sms_ntsc_rgb_t const* kernelx1 = kernel0;\
|
||||
sms_ntsc_rgb_t const* kernelx2 = kernel0
|
||||
|
||||
#define SMS_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
|
||||
sms_ntsc_rgb_t raw_ =\
|
||||
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
|
||||
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
|
||||
SMS_NTSC_CLAMP_( raw_, shift );\
|
||||
SMS_NTSC_RGB_OUT_( rgb_out, bits, shift );\
|
||||
}
|
||||
|
||||
/* common ntsc macros */
|
||||
#define sms_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
|
||||
#define sms_ntsc_clamp_mask (sms_ntsc_rgb_builder * 3 / 2)
|
||||
#define sms_ntsc_clamp_add (sms_ntsc_rgb_builder * 0x101)
|
||||
#define SMS_NTSC_CLAMP_( io, shift ) {\
|
||||
sms_ntsc_rgb_t sub = (io) >> (9-(shift)) & sms_ntsc_clamp_mask;\
|
||||
sms_ntsc_rgb_t clamp = sms_ntsc_clamp_add - sub;\
|
||||
io |= clamp;\
|
||||
clamp -= sub;\
|
||||
io &= clamp;\
|
||||
}
|
||||
|
||||
#define SMS_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
|
||||
unsigned color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
|
||||
}
|
||||
|
||||
/* x is always zero except in snes_ntsc library */
|
||||
#define SMS_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,27 +1,27 @@
|
||||
/* Configure library by modifying this file */
|
||||
|
||||
#ifndef SMS_NTSC_CONFIG_H
|
||||
#define SMS_NTSC_CONFIG_H
|
||||
|
||||
/* Format of source pixels */
|
||||
#define SMS_NTSC_IN_FORMAT SMS_NTSC_RGB16
|
||||
/* #define SMS_NTSC_IN_FORMAT SMS_NTSC_RGB15 */
|
||||
/* #define SMS_NTSC_IN_FORMAT SMS_NTSC_BGR12 */
|
||||
|
||||
/* The following affect the built-in blitter only; a custom blitter can
|
||||
handle things however it wants. */
|
||||
|
||||
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
|
||||
#define SMS_NTSC_OUT_DEPTH 16
|
||||
|
||||
/* Type of input pixel values */
|
||||
#define SMS_NTSC_IN_T unsigned short
|
||||
|
||||
/* Each raw pixel input value is passed through this. You might want to mask
|
||||
the pixel index if you use the high bits as flags, etc. */
|
||||
#define SMS_NTSC_ADJ_IN( in ) in
|
||||
|
||||
/* For each pixel, this is the basic operation:
|
||||
output_color = SMS_NTSC_ADJ_IN( SMS_NTSC_IN_T ) */
|
||||
|
||||
#endif
|
||||
/* Configure library by modifying this file */
|
||||
|
||||
#ifndef SMS_NTSC_CONFIG_H
|
||||
#define SMS_NTSC_CONFIG_H
|
||||
|
||||
/* Format of source pixels */
|
||||
#define SMS_NTSC_IN_FORMAT SMS_NTSC_RGB16
|
||||
/* #define SMS_NTSC_IN_FORMAT SMS_NTSC_RGB15 */
|
||||
/* #define SMS_NTSC_IN_FORMAT SMS_NTSC_BGR12 */
|
||||
|
||||
/* The following affect the built-in blitter only; a custom blitter can
|
||||
handle things however it wants. */
|
||||
|
||||
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
|
||||
#define SMS_NTSC_OUT_DEPTH 16
|
||||
|
||||
/* Type of input pixel values */
|
||||
#define SMS_NTSC_IN_T unsigned short
|
||||
|
||||
/* Each raw pixel input value is passed through this. You might want to mask
|
||||
the pixel index if you use the high bits as flags, etc. */
|
||||
#define SMS_NTSC_ADJ_IN( in ) in
|
||||
|
||||
/* For each pixel, this is the basic operation:
|
||||
output_color = SMS_NTSC_ADJ_IN( SMS_NTSC_IN_T ) */
|
||||
|
||||
#endif
|
||||
|
@ -1,439 +1,439 @@
|
||||
/* sms_ntsc 0.2.3. http://www.slack.net/~ant/ */
|
||||
|
||||
/* Common implementation of NTSC filters */
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copyright (C) 2006 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#define DISABLE_CORRECTION 0
|
||||
|
||||
#undef PI
|
||||
#define PI 3.14159265358979323846f
|
||||
|
||||
#ifndef LUMA_CUTOFF
|
||||
#define LUMA_CUTOFF 0.20
|
||||
#endif
|
||||
#ifndef gamma_size
|
||||
#define gamma_size 1
|
||||
#endif
|
||||
#ifndef rgb_bits
|
||||
#define rgb_bits 8
|
||||
#endif
|
||||
#ifndef artifacts_max
|
||||
#define artifacts_max (artifacts_mid * 1.5f)
|
||||
#endif
|
||||
#ifndef fringing_max
|
||||
#define fringing_max (fringing_mid * 2)
|
||||
#endif
|
||||
#ifndef STD_HUE_CONDITION
|
||||
#define STD_HUE_CONDITION( setup ) 1
|
||||
#endif
|
||||
|
||||
#define ext_decoder_hue (std_decoder_hue + 15)
|
||||
#define rgb_unit (1 << rgb_bits)
|
||||
#define rgb_offset (rgb_unit * 2 + 0.5f)
|
||||
|
||||
enum { burst_size = sms_ntsc_entry_size / burst_count };
|
||||
enum { kernel_half = 16 };
|
||||
enum { kernel_size = kernel_half * 2 + 1 };
|
||||
|
||||
typedef struct init_t
|
||||
{
|
||||
float to_rgb [burst_count * 6];
|
||||
float to_float [gamma_size];
|
||||
float contrast;
|
||||
float brightness;
|
||||
float artifacts;
|
||||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
} init_t;
|
||||
|
||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
||||
float t;\
|
||||
t = i * cos_b - q * sin_b;\
|
||||
q = i * sin_b + q * cos_b;\
|
||||
i = t;\
|
||||
}
|
||||
|
||||
static void init_filters( init_t* impl, sms_ntsc_setup_t const* setup )
|
||||
{
|
||||
#if rescale_out > 1
|
||||
float kernels [kernel_size * 2];
|
||||
#else
|
||||
float* const kernels = impl->kernel;
|
||||
#endif
|
||||
|
||||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
|
||||
float const maxh = 32;
|
||||
float const pow_a_n = (float) pow( rolloff, maxh );
|
||||
float sum;
|
||||
int i;
|
||||
/* quadratic mapping to reduce negative (blurring) range */
|
||||
float to_angle = (float) setup->resolution + 1;
|
||||
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
|
||||
|
||||
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = i - kernel_half;
|
||||
float angle = x * to_angle;
|
||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
||||
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
|
||||
{
|
||||
float rolloff_cos_a = rolloff * (float) cos( angle );
|
||||
float num = 1 - rolloff_cos_a -
|
||||
pow_a_n * (float) cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
|
||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
float dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply blackman window and find sum */
|
||||
sum = 0;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
float x = PI * 2 / (kernel_half * 2) * i;
|
||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
}
|
||||
|
||||
/* normalize kernel */
|
||||
sum = 1.0f / sum;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
|
||||
/* generate chroma (iq) filter using gaussian kernel */
|
||||
{
|
||||
float const cutoff_factor = -0.03125f;
|
||||
float cutoff = (float) setup->bleed;
|
||||
int i;
|
||||
|
||||
if ( cutoff < 0 )
|
||||
{
|
||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= -30.0f / 0.65f;
|
||||
}
|
||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
||||
|
||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
||||
|
||||
/* normalize even and odd phases separately */
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
float sum = 0;
|
||||
int x;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
sum += kernels [x];
|
||||
|
||||
sum = 1.0f / sum;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
{
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
printf( "luma:\n" );
|
||||
for ( i = kernel_size; i < kernel_size * 2; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
printf( "chroma:\n" );
|
||||
for ( i = 0; i < kernel_size; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
*/
|
||||
|
||||
/* generate linear rescale kernels */
|
||||
#if rescale_out > 1
|
||||
{
|
||||
float weight = 1.0f;
|
||||
float* out = impl->kernel;
|
||||
int n = rescale_out;
|
||||
do
|
||||
{
|
||||
float remain = 0;
|
||||
int i;
|
||||
weight -= 1.0f / rescale_in;
|
||||
for ( i = 0; i < kernel_size * 2; i++ )
|
||||
{
|
||||
float cur = kernels [i];
|
||||
float m = cur * weight;
|
||||
*out++ = m + remain;
|
||||
remain = cur - m;
|
||||
}
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static float const default_decoder [6] =
|
||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
|
||||
static void init( init_t* impl, sms_ntsc_setup_t const* setup )
|
||||
{
|
||||
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
||||
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
||||
#ifdef default_palette_contrast
|
||||
if ( !setup->palette )
|
||||
impl->contrast *= default_palette_contrast;
|
||||
#endif
|
||||
|
||||
impl->artifacts = (float) setup->artifacts;
|
||||
if ( impl->artifacts > 0 )
|
||||
impl->artifacts *= artifacts_max - artifacts_mid;
|
||||
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
|
||||
|
||||
impl->fringing = (float) setup->fringing;
|
||||
if ( impl->fringing > 0 )
|
||||
impl->fringing *= fringing_max - fringing_mid;
|
||||
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
|
||||
|
||||
init_filters( impl, setup );
|
||||
|
||||
/* generate gamma table */
|
||||
if ( gamma_size > 1 )
|
||||
{
|
||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
||||
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
|
||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
||||
int i;
|
||||
for ( i = 0; i < gamma_size; i++ )
|
||||
impl->to_float [i] =
|
||||
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
|
||||
}
|
||||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
float sat = (float) setup->saturation + 1;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
if ( !decoder )
|
||||
{
|
||||
decoder = default_decoder;
|
||||
if ( STD_HUE_CONDITION( setup ) )
|
||||
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
|
||||
}
|
||||
|
||||
{
|
||||
float s = (float) sin( hue ) * sat;
|
||||
float c = (float) cos( hue ) * sat;
|
||||
float* out = impl->to_rgb;
|
||||
int n;
|
||||
|
||||
n = burst_count;
|
||||
do
|
||||
{
|
||||
float const* in = decoder;
|
||||
int n = 3;
|
||||
do
|
||||
{
|
||||
float i = *in++;
|
||||
float q = *in++;
|
||||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
while ( --n );
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* kernel generation */
|
||||
|
||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
||||
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
|
||||
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
|
||||
)
|
||||
|
||||
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
|
||||
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
|
||||
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
|
||||
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
|
||||
)
|
||||
|
||||
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
|
||||
|
||||
enum { rgb_kernel_size = burst_size / alignment_count };
|
||||
enum { rgb_bias = rgb_unit * 2 * sms_ntsc_rgb_builder };
|
||||
|
||||
typedef struct pixel_info_t
|
||||
{
|
||||
int offset;
|
||||
float negate;
|
||||
float kernel [4];
|
||||
} pixel_info_t;
|
||||
|
||||
#if rescale_in > 1
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
||||
(kernel_size * 2 * scaled))
|
||||
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#else
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
(kernel_size / 2 + (ntsc) - (scaled)),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#endif
|
||||
|
||||
extern pixel_info_t const sms_ntsc_pixels [alignment_count];
|
||||
|
||||
/* Generate pixel at all burst phases and column alignments */
|
||||
static void gen_kernel( init_t* impl, float y, float i, float q, sms_ntsc_rgb_t* out )
|
||||
{
|
||||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb;
|
||||
int burst_remain = burst_count;
|
||||
y -= rgb_offset;
|
||||
do
|
||||
{
|
||||
/* Encode yiq into *two* composite signals (to allow control over artifacting).
|
||||
Convolve these with kernels which: filter respective components, apply
|
||||
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
|
||||
into integer. Based on algorithm by NewRisingSun. */
|
||||
pixel_info_t const* pixel = sms_ntsc_pixels;
|
||||
int alignment_remain = alignment_count;
|
||||
do
|
||||
{
|
||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
||||
float const yy = y * impl->fringing * pixel->negate;
|
||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
||||
|
||||
float const factor = impl->artifacts * pixel->negate;
|
||||
float const ii = i * factor;
|
||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
||||
|
||||
float const qq = q * factor;
|
||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
||||
|
||||
float const* k = &impl->kernel [pixel->offset];
|
||||
int n;
|
||||
++pixel;
|
||||
for ( n = rgb_kernel_size; n; --n )
|
||||
{
|
||||
float i = k[0]*ic0 + k[2]*ic2;
|
||||
float q = k[1]*qc1 + k[3]*qc3;
|
||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
||||
if ( rescale_out <= 1 )
|
||||
k--;
|
||||
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
||||
k += kernel_size * 2 - 1;
|
||||
else
|
||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
||||
{
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
|
||||
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( alignment_count > 1 && --alignment_remain );
|
||||
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
|
||||
to_rgb += 6;
|
||||
|
||||
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
|
||||
}
|
||||
while ( --burst_remain );
|
||||
}
|
||||
|
||||
static void correct_errors( sms_ntsc_rgb_t color, sms_ntsc_rgb_t* out );
|
||||
|
||||
#if DISABLE_CORRECTION
|
||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
||||
#else
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
sms_ntsc_rgb_t fourth = (error + 2 * sms_ntsc_rgb_builder) >> 2;\
|
||||
fourth &= (rgb_bias >> 1) - sms_ntsc_rgb_builder;\
|
||||
fourth -= rgb_bias >> 2;\
|
||||
out [a] += fourth;\
|
||||
out [b] += fourth;\
|
||||
out [c] += fourth;\
|
||||
out [i] += error - (fourth * 3);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#define RGB_PALETTE_OUT( rgb, out_ )\
|
||||
{\
|
||||
unsigned char* out = (out_);\
|
||||
sms_ntsc_rgb_t clamped = (rgb);\
|
||||
SMS_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
|
||||
out [0] = (unsigned char) (clamped >> 21);\
|
||||
out [1] = (unsigned char) (clamped >> 11);\
|
||||
out [2] = (unsigned char) (clamped >> 1);\
|
||||
}
|
||||
|
||||
/* blitter related */
|
||||
|
||||
#ifndef restrict
|
||||
#if defined (__GNUC__)
|
||||
#define restrict __restrict__
|
||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
||||
#define restrict __restrict
|
||||
#else
|
||||
/* no support for restricted pointers */
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if SMS_NTSC_OUT_DEPTH <= 16
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef unsigned short sms_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 16-bit int type"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int sms_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long sms_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 32-bit int type"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* sms_ntsc 0.2.3. http://www.slack.net/~ant/ */
|
||||
|
||||
/* Common implementation of NTSC filters */
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copyright (C) 2006 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#define DISABLE_CORRECTION 0
|
||||
|
||||
#undef PI
|
||||
#define PI 3.14159265358979323846f
|
||||
|
||||
#ifndef LUMA_CUTOFF
|
||||
#define LUMA_CUTOFF 0.20
|
||||
#endif
|
||||
#ifndef gamma_size
|
||||
#define gamma_size 1
|
||||
#endif
|
||||
#ifndef rgb_bits
|
||||
#define rgb_bits 8
|
||||
#endif
|
||||
#ifndef artifacts_max
|
||||
#define artifacts_max (artifacts_mid * 1.5f)
|
||||
#endif
|
||||
#ifndef fringing_max
|
||||
#define fringing_max (fringing_mid * 2)
|
||||
#endif
|
||||
#ifndef STD_HUE_CONDITION
|
||||
#define STD_HUE_CONDITION( setup ) 1
|
||||
#endif
|
||||
|
||||
#define ext_decoder_hue (std_decoder_hue + 15)
|
||||
#define rgb_unit (1 << rgb_bits)
|
||||
#define rgb_offset (rgb_unit * 2 + 0.5f)
|
||||
|
||||
enum { burst_size = sms_ntsc_entry_size / burst_count };
|
||||
enum { kernel_half = 16 };
|
||||
enum { kernel_size = kernel_half * 2 + 1 };
|
||||
|
||||
typedef struct init_t
|
||||
{
|
||||
float to_rgb [burst_count * 6];
|
||||
float to_float [gamma_size];
|
||||
float contrast;
|
||||
float brightness;
|
||||
float artifacts;
|
||||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
} init_t;
|
||||
|
||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
||||
float t;\
|
||||
t = i * cos_b - q * sin_b;\
|
||||
q = i * sin_b + q * cos_b;\
|
||||
i = t;\
|
||||
}
|
||||
|
||||
static void init_filters( init_t* impl, sms_ntsc_setup_t const* setup )
|
||||
{
|
||||
#if rescale_out > 1
|
||||
float kernels [kernel_size * 2];
|
||||
#else
|
||||
float* const kernels = impl->kernel;
|
||||
#endif
|
||||
|
||||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
|
||||
float const maxh = 32;
|
||||
float const pow_a_n = (float) pow( rolloff, maxh );
|
||||
float sum;
|
||||
int i;
|
||||
/* quadratic mapping to reduce negative (blurring) range */
|
||||
float to_angle = (float) setup->resolution + 1;
|
||||
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
|
||||
|
||||
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = i - kernel_half;
|
||||
float angle = x * to_angle;
|
||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
||||
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
|
||||
{
|
||||
float rolloff_cos_a = rolloff * (float) cos( angle );
|
||||
float num = 1 - rolloff_cos_a -
|
||||
pow_a_n * (float) cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
|
||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
float dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply blackman window and find sum */
|
||||
sum = 0;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
float x = PI * 2 / (kernel_half * 2) * i;
|
||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
}
|
||||
|
||||
/* normalize kernel */
|
||||
sum = 1.0f / sum;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
|
||||
/* generate chroma (iq) filter using gaussian kernel */
|
||||
{
|
||||
float const cutoff_factor = -0.03125f;
|
||||
float cutoff = (float) setup->bleed;
|
||||
int i;
|
||||
|
||||
if ( cutoff < 0 )
|
||||
{
|
||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= -30.0f / 0.65f;
|
||||
}
|
||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
||||
|
||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
||||
|
||||
/* normalize even and odd phases separately */
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
float sum = 0;
|
||||
int x;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
sum += kernels [x];
|
||||
|
||||
sum = 1.0f / sum;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
{
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
printf( "luma:\n" );
|
||||
for ( i = kernel_size; i < kernel_size * 2; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
printf( "chroma:\n" );
|
||||
for ( i = 0; i < kernel_size; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
*/
|
||||
|
||||
/* generate linear rescale kernels */
|
||||
#if rescale_out > 1
|
||||
{
|
||||
float weight = 1.0f;
|
||||
float* out = impl->kernel;
|
||||
int n = rescale_out;
|
||||
do
|
||||
{
|
||||
float remain = 0;
|
||||
int i;
|
||||
weight -= 1.0f / rescale_in;
|
||||
for ( i = 0; i < kernel_size * 2; i++ )
|
||||
{
|
||||
float cur = kernels [i];
|
||||
float m = cur * weight;
|
||||
*out++ = m + remain;
|
||||
remain = cur - m;
|
||||
}
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static float const default_decoder [6] =
|
||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
|
||||
static void init( init_t* impl, sms_ntsc_setup_t const* setup )
|
||||
{
|
||||
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
||||
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
||||
#ifdef default_palette_contrast
|
||||
if ( !setup->palette )
|
||||
impl->contrast *= default_palette_contrast;
|
||||
#endif
|
||||
|
||||
impl->artifacts = (float) setup->artifacts;
|
||||
if ( impl->artifacts > 0 )
|
||||
impl->artifacts *= artifacts_max - artifacts_mid;
|
||||
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
|
||||
|
||||
impl->fringing = (float) setup->fringing;
|
||||
if ( impl->fringing > 0 )
|
||||
impl->fringing *= fringing_max - fringing_mid;
|
||||
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
|
||||
|
||||
init_filters( impl, setup );
|
||||
|
||||
/* generate gamma table */
|
||||
if ( gamma_size > 1 )
|
||||
{
|
||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
||||
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
|
||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
||||
int i;
|
||||
for ( i = 0; i < gamma_size; i++ )
|
||||
impl->to_float [i] =
|
||||
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
|
||||
}
|
||||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
float sat = (float) setup->saturation + 1;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
if ( !decoder )
|
||||
{
|
||||
decoder = default_decoder;
|
||||
if ( STD_HUE_CONDITION( setup ) )
|
||||
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
|
||||
}
|
||||
|
||||
{
|
||||
float s = (float) sin( hue ) * sat;
|
||||
float c = (float) cos( hue ) * sat;
|
||||
float* out = impl->to_rgb;
|
||||
int n;
|
||||
|
||||
n = burst_count;
|
||||
do
|
||||
{
|
||||
float const* in = decoder;
|
||||
int n = 3;
|
||||
do
|
||||
{
|
||||
float i = *in++;
|
||||
float q = *in++;
|
||||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
while ( --n );
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* kernel generation */
|
||||
|
||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
||||
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
|
||||
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
|
||||
)
|
||||
|
||||
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
|
||||
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
|
||||
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
|
||||
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
|
||||
)
|
||||
|
||||
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
|
||||
|
||||
enum { rgb_kernel_size = burst_size / alignment_count };
|
||||
enum { rgb_bias = rgb_unit * 2 * sms_ntsc_rgb_builder };
|
||||
|
||||
typedef struct pixel_info_t
|
||||
{
|
||||
int offset;
|
||||
float negate;
|
||||
float kernel [4];
|
||||
} pixel_info_t;
|
||||
|
||||
#if rescale_in > 1
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
||||
(kernel_size * 2 * scaled))
|
||||
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#else
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
(kernel_size / 2 + (ntsc) - (scaled)),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#endif
|
||||
|
||||
extern pixel_info_t const sms_ntsc_pixels [alignment_count];
|
||||
|
||||
/* Generate pixel at all burst phases and column alignments */
|
||||
static void gen_kernel( init_t* impl, float y, float i, float q, sms_ntsc_rgb_t* out )
|
||||
{
|
||||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb;
|
||||
int burst_remain = burst_count;
|
||||
y -= rgb_offset;
|
||||
do
|
||||
{
|
||||
/* Encode yiq into *two* composite signals (to allow control over artifacting).
|
||||
Convolve these with kernels which: filter respective components, apply
|
||||
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
|
||||
into integer. Based on algorithm by NewRisingSun. */
|
||||
pixel_info_t const* pixel = sms_ntsc_pixels;
|
||||
int alignment_remain = alignment_count;
|
||||
do
|
||||
{
|
||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
||||
float const yy = y * impl->fringing * pixel->negate;
|
||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
||||
|
||||
float const factor = impl->artifacts * pixel->negate;
|
||||
float const ii = i * factor;
|
||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
||||
|
||||
float const qq = q * factor;
|
||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
||||
|
||||
float const* k = &impl->kernel [pixel->offset];
|
||||
int n;
|
||||
++pixel;
|
||||
for ( n = rgb_kernel_size; n; --n )
|
||||
{
|
||||
float i = k[0]*ic0 + k[2]*ic2;
|
||||
float q = k[1]*qc1 + k[3]*qc3;
|
||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
||||
if ( rescale_out <= 1 )
|
||||
k--;
|
||||
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
||||
k += kernel_size * 2 - 1;
|
||||
else
|
||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
||||
{
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
|
||||
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( alignment_count > 1 && --alignment_remain );
|
||||
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
|
||||
to_rgb += 6;
|
||||
|
||||
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
|
||||
}
|
||||
while ( --burst_remain );
|
||||
}
|
||||
|
||||
static void correct_errors( sms_ntsc_rgb_t color, sms_ntsc_rgb_t* out );
|
||||
|
||||
#if DISABLE_CORRECTION
|
||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
||||
#else
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
sms_ntsc_rgb_t fourth = (error + 2 * sms_ntsc_rgb_builder) >> 2;\
|
||||
fourth &= (rgb_bias >> 1) - sms_ntsc_rgb_builder;\
|
||||
fourth -= rgb_bias >> 2;\
|
||||
out [a] += fourth;\
|
||||
out [b] += fourth;\
|
||||
out [c] += fourth;\
|
||||
out [i] += error - (fourth * 3);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#define RGB_PALETTE_OUT( rgb, out_ )\
|
||||
{\
|
||||
unsigned char* out = (out_);\
|
||||
sms_ntsc_rgb_t clamped = (rgb);\
|
||||
SMS_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
|
||||
out [0] = (unsigned char) (clamped >> 21);\
|
||||
out [1] = (unsigned char) (clamped >> 11);\
|
||||
out [2] = (unsigned char) (clamped >> 1);\
|
||||
}
|
||||
|
||||
/* blitter related */
|
||||
|
||||
#ifndef restrict
|
||||
#if defined (__GNUC__)
|
||||
#define restrict __restrict__
|
||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
||||
#define restrict __restrict
|
||||
#else
|
||||
/* no support for restricted pointers */
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if SMS_NTSC_OUT_DEPTH <= 16
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef unsigned short sms_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 16-bit int type"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int sms_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long sms_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 32-bit int type"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -11,19 +11,20 @@
|
||||
#include "z80.h"
|
||||
#include "system.h"
|
||||
#include "genesis.h"
|
||||
#include "vdp.h"
|
||||
#include "render.h"
|
||||
#include "vdp_ctrl.h"
|
||||
#include "vdp_render.h"
|
||||
#include "mem68k.h"
|
||||
#include "memz80.h"
|
||||
#include "membnk.h"
|
||||
#include "gen_io.h"
|
||||
#include "gen_input.h"
|
||||
#include "io_ctrl.h"
|
||||
#include "input.h"
|
||||
#include "state.h"
|
||||
#include "sound.h"
|
||||
#include "sn76489.h"
|
||||
#include "ym2612.h"
|
||||
#include "loadrom.h"
|
||||
#include "cart_hw.h"
|
||||
#include "sms_cart.h"
|
||||
#include "md_cart.h"
|
||||
#include "eeprom.h"
|
||||
#include "sram.h"
|
||||
#include "ggenie.h"
|
||||
|
@ -1,351 +1,351 @@
|
||||
/* Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
|
||||
/* Copyright (C) 2004-2006 Shay Green. */
|
||||
/* C Conversion by Eke-Eke for use in Genesis Plus (2009). */
|
||||
|
||||
#include "Fir_Resampler.h"
|
||||
#include "shared.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
/* sound buffer */
|
||||
static sample_t *buffer = NULL;
|
||||
static int buffer_size = 0;
|
||||
|
||||
static sample_t impulses[MAX_RES][WIDTH];
|
||||
static sample_t* write_pos = NULL;
|
||||
static int res = 1;
|
||||
static int imp_phase = 0;
|
||||
static unsigned long skip_bits = 0;
|
||||
static int step = STEREO;
|
||||
static int input_per_cycle;
|
||||
static double ratio = 1.0;
|
||||
|
||||
static void gen_sinc(double rolloff, int width, double offset, double spacing, double scale, int count, sample_t *out )
|
||||
{
|
||||
double w, rolloff_cos_a, num, den, sinc;
|
||||
double const maxh = 256;
|
||||
double const fstep = M_PI / maxh * spacing;
|
||||
double const to_w = maxh * 2 / width;
|
||||
double const pow_a_n = pow( rolloff, maxh );
|
||||
scale /= maxh * 2;
|
||||
|
||||
double angle = (count / 2 - 1 + offset) * -fstep;
|
||||
|
||||
while ( count-- )
|
||||
{
|
||||
*out++ = 0;
|
||||
w = angle * to_w;
|
||||
if ( fabs( w ) < M_PI )
|
||||
{
|
||||
rolloff_cos_a = rolloff * cos( angle );
|
||||
num = 1 - rolloff_cos_a -
|
||||
pow_a_n * cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * cos( (maxh - 1) * angle );
|
||||
den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
sinc = scale * num / den - scale;
|
||||
|
||||
out [-1] = (short) (cos( w ) * sinc + sinc);
|
||||
}
|
||||
angle += fstep;
|
||||
}
|
||||
}
|
||||
|
||||
/*static int available( long input_count )
|
||||
{
|
||||
int cycle_count = input_count / input_per_cycle;
|
||||
int output_count = cycle_count * res * STEREO;
|
||||
input_count -= cycle_count * input_per_cycle;
|
||||
|
||||
unsigned long skip = skip_bits >> imp_phase;
|
||||
int remain = res - imp_phase;
|
||||
while ( input_count >= 0 )
|
||||
{
|
||||
input_count -= step + (skip & 1) * STEREO;
|
||||
skip >>= 1;
|
||||
if ( !--remain )
|
||||
{
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
output_count += 2;
|
||||
}
|
||||
return output_count;
|
||||
}
|
||||
*/
|
||||
int Fir_Resampler_avail()
|
||||
{
|
||||
long count = 0;
|
||||
sample_t* in = buffer;
|
||||
sample_t* end_pos = write_pos;
|
||||
unsigned long skip = skip_bits >> imp_phase;
|
||||
int remain = res - imp_phase;
|
||||
if ( end_pos - in >= WIDTH * STEREO )
|
||||
{
|
||||
end_pos -= WIDTH * STEREO;
|
||||
do
|
||||
{
|
||||
count++;
|
||||
remain--;
|
||||
in += (skip * STEREO) & STEREO;
|
||||
skip >>= 1;
|
||||
in += step;
|
||||
|
||||
if ( !remain )
|
||||
{
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
}
|
||||
while ( in <= end_pos );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int Fir_Resampler_initialize( int new_size )
|
||||
{
|
||||
res = 1;
|
||||
skip_bits = 0;
|
||||
imp_phase = 0;
|
||||
step = STEREO;
|
||||
ratio = 1.0;
|
||||
buffer = (sample_t *) realloc( buffer, (new_size + WRITE_OFFSET) * sizeof (sample_t) );
|
||||
write_pos = 0;
|
||||
if ( !buffer ) return 0;
|
||||
buffer_size = new_size + WRITE_OFFSET;
|
||||
Fir_Resampler_clear();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Fir_Resampler_shutdown( void )
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
buffer = 0;
|
||||
buffer_size = 0;
|
||||
write_pos = 0;
|
||||
}
|
||||
|
||||
void Fir_Resampler_clear()
|
||||
{
|
||||
imp_phase = 0;
|
||||
if ( buffer_size )
|
||||
{
|
||||
write_pos = &buffer [WRITE_OFFSET];
|
||||
memset( buffer, 0, buffer_size * sizeof (sample_t) );
|
||||
}
|
||||
}
|
||||
|
||||
double Fir_Resampler_time_ratio( double new_factor, double rolloff )
|
||||
{
|
||||
ratio = new_factor;
|
||||
|
||||
int i, r;
|
||||
double nearest, error;
|
||||
double fstep = 0.0;
|
||||
double least_error = 2;
|
||||
double pos = 0.0;
|
||||
res = -1;
|
||||
|
||||
#ifdef NGC
|
||||
u32 level = IRQ_Disable();
|
||||
#endif
|
||||
|
||||
for ( r = 1; r <= MAX_RES; r++ )
|
||||
{
|
||||
pos += ratio;
|
||||
nearest = floor( pos + 0.5 );
|
||||
error = fabs( pos - nearest );
|
||||
if ( error < least_error )
|
||||
{
|
||||
res = r;
|
||||
fstep = nearest / res;
|
||||
least_error = error;
|
||||
}
|
||||
}
|
||||
|
||||
skip_bits = 0;
|
||||
|
||||
step = STEREO * (int) floor( fstep );
|
||||
|
||||
ratio = fstep;
|
||||
fstep = fmod( fstep, 1.0 );
|
||||
|
||||
double filter = (ratio < 1.0) ? 1.0 : 1.0 / ratio;
|
||||
pos = 0.0;
|
||||
input_per_cycle = 0;
|
||||
|
||||
memset(impulses, 0, MAX_RES*WIDTH*sizeof(sample_t));
|
||||
|
||||
for ( i = 0; i < res; i++ )
|
||||
{
|
||||
gen_sinc( rolloff, (int) (WIDTH * filter + 1) & ~1, pos, filter,
|
||||
(double) (0x7FFF * GAIN * filter),
|
||||
(int) WIDTH, impulses[i] );
|
||||
|
||||
pos += fstep;
|
||||
input_per_cycle += step;
|
||||
if ( pos >= 0.9999999 )
|
||||
{
|
||||
pos -= 1.0;
|
||||
skip_bits |= 1 << i;
|
||||
input_per_cycle++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NGC
|
||||
IRQ_Restore(level);
|
||||
#endif
|
||||
|
||||
Fir_Resampler_clear();
|
||||
|
||||
return ratio;
|
||||
}
|
||||
|
||||
/* Current ratio */
|
||||
double Fir_Resampler_ratio( void )
|
||||
{
|
||||
return ratio;
|
||||
}
|
||||
|
||||
/* Number of input samples that can be written */
|
||||
int Fir_Resampler_max_write( void )
|
||||
{
|
||||
return buffer + buffer_size - write_pos;
|
||||
}
|
||||
|
||||
/* Pointer to place to write input samples */
|
||||
sample_t* Fir_Resampler_buffer( void )
|
||||
{
|
||||
return write_pos;
|
||||
}
|
||||
|
||||
/* Number of input samples in buffer */
|
||||
int Fir_Resampler_written( void )
|
||||
{
|
||||
return write_pos - &buffer [WRITE_OFFSET];
|
||||
}
|
||||
|
||||
/* Number of output samples available */
|
||||
/*int Fir_Resampler_avail( void )
|
||||
{
|
||||
return available( write_pos - &buffer [WIDTH * STEREO] );
|
||||
}*/
|
||||
|
||||
void Fir_Resampler_write( long count )
|
||||
{
|
||||
write_pos += count;
|
||||
}
|
||||
|
||||
int Fir_Resampler_read( sample_t* out, long count )
|
||||
{
|
||||
sample_t* out_ = out;
|
||||
sample_t* in = buffer;
|
||||
sample_t* end_pos = write_pos;
|
||||
unsigned long skip = skip_bits >> imp_phase;
|
||||
sample_t const* imp = impulses [imp_phase];
|
||||
int remain = res - imp_phase;
|
||||
int n;
|
||||
int pt0,pt1;
|
||||
sample_t* i;
|
||||
long l,r;
|
||||
|
||||
if ( end_pos - in >= WIDTH * STEREO )
|
||||
{
|
||||
end_pos -= WIDTH * STEREO;
|
||||
do
|
||||
{
|
||||
count--;
|
||||
|
||||
if ( count < 0 )
|
||||
break;
|
||||
|
||||
/* accumulate in extended precision */
|
||||
l = 0;
|
||||
r = 0;
|
||||
|
||||
i = in;
|
||||
|
||||
for ( n = WIDTH / 2; n; --n )
|
||||
{
|
||||
pt0 = imp [0];
|
||||
l += pt0 * i [0];
|
||||
r += pt0 * i [1];
|
||||
pt1 = imp [1];
|
||||
imp += 2;
|
||||
l += pt1 * i [2];
|
||||
r += pt1 * i [3];
|
||||
i += 4;
|
||||
}
|
||||
|
||||
remain--;
|
||||
|
||||
l >>= 15;
|
||||
r >>= 15;
|
||||
|
||||
in += (skip * STEREO) & STEREO;
|
||||
skip >>= 1;
|
||||
in += step;
|
||||
|
||||
if ( !remain )
|
||||
{
|
||||
imp = impulses [0];
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
|
||||
*out++ = (sample_t) l;
|
||||
*out++ = (sample_t) r;
|
||||
}
|
||||
while ( in <= end_pos );
|
||||
}
|
||||
|
||||
imp_phase = res - remain;
|
||||
|
||||
int left = write_pos - in;
|
||||
write_pos = &buffer [left];
|
||||
memmove( buffer, in, left * sizeof *in );
|
||||
|
||||
return out - out_;
|
||||
}
|
||||
|
||||
/* fixed (Eke_Eke) */
|
||||
int Fir_Resampler_input_needed( long output_count )
|
||||
{
|
||||
long input_count = 0;
|
||||
|
||||
unsigned long skip = skip_bits >> imp_phase;
|
||||
int remain = res - imp_phase;
|
||||
while ( (output_count) > 0 )
|
||||
{
|
||||
input_count += step + (skip & 1) * STEREO;
|
||||
skip >>= 1;
|
||||
if ( !--remain )
|
||||
{
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
output_count --;
|
||||
}
|
||||
|
||||
long input_extra = input_count - (write_pos - &buffer [WRITE_OFFSET]);
|
||||
if ( input_extra < 0 )
|
||||
input_extra = 0;
|
||||
return (input_extra >> 1);
|
||||
}
|
||||
|
||||
int Fir_Resampler_skip_input( long count )
|
||||
{
|
||||
int remain = write_pos - buffer;
|
||||
int max_count = remain - WIDTH * STEREO;
|
||||
if ( count > max_count )
|
||||
count = max_count;
|
||||
|
||||
remain -= count;
|
||||
write_pos = &buffer [remain];
|
||||
memmove( buffer, &buffer [count], remain * sizeof buffer [0] );
|
||||
|
||||
return count;
|
||||
}
|
||||
/* Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
|
||||
/* Copyright (C) 2004-2006 Shay Green. */
|
||||
/* C Conversion by Eke-Eke for use in Genesis Plus (2009). */
|
||||
|
||||
#include "Fir_Resampler.h"
|
||||
#include "shared.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
/* sound buffer */
|
||||
static sample_t *buffer = NULL;
|
||||
static int buffer_size = 0;
|
||||
|
||||
static sample_t impulses[MAX_RES][WIDTH];
|
||||
static sample_t* write_pos = NULL;
|
||||
static int res = 1;
|
||||
static int imp_phase = 0;
|
||||
static unsigned long skip_bits = 0;
|
||||
static int step = STEREO;
|
||||
static int input_per_cycle;
|
||||
static double ratio = 1.0;
|
||||
|
||||
static void gen_sinc(double rolloff, int width, double offset, double spacing, double scale, int count, sample_t *out )
|
||||
{
|
||||
double w, rolloff_cos_a, num, den, sinc;
|
||||
double const maxh = 256;
|
||||
double const fstep = M_PI / maxh * spacing;
|
||||
double const to_w = maxh * 2 / width;
|
||||
double const pow_a_n = pow( rolloff, maxh );
|
||||
scale /= maxh * 2;
|
||||
|
||||
double angle = (count / 2 - 1 + offset) * -fstep;
|
||||
|
||||
while ( count-- )
|
||||
{
|
||||
*out++ = 0;
|
||||
w = angle * to_w;
|
||||
if ( fabs( w ) < M_PI )
|
||||
{
|
||||
rolloff_cos_a = rolloff * cos( angle );
|
||||
num = 1 - rolloff_cos_a -
|
||||
pow_a_n * cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * cos( (maxh - 1) * angle );
|
||||
den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
sinc = scale * num / den - scale;
|
||||
|
||||
out [-1] = (short) (cos( w ) * sinc + sinc);
|
||||
}
|
||||
angle += fstep;
|
||||
}
|
||||
}
|
||||
|
||||
/*static int available( long input_count )
|
||||
{
|
||||
int cycle_count = input_count / input_per_cycle;
|
||||
int output_count = cycle_count * res * STEREO;
|
||||
input_count -= cycle_count * input_per_cycle;
|
||||
|
||||
unsigned long skip = skip_bits >> imp_phase;
|
||||
int remain = res - imp_phase;
|
||||
while ( input_count >= 0 )
|
||||
{
|
||||
input_count -= step + (skip & 1) * STEREO;
|
||||
skip >>= 1;
|
||||
if ( !--remain )
|
||||
{
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
output_count += 2;
|
||||
}
|
||||
return output_count;
|
||||
}
|
||||
*/
|
||||
int Fir_Resampler_avail()
|
||||
{
|
||||
long count = 0;
|
||||
sample_t* in = buffer;
|
||||
sample_t* end_pos = write_pos;
|
||||
unsigned long skip = skip_bits >> imp_phase;
|
||||
int remain = res - imp_phase;
|
||||
if ( end_pos - in >= WIDTH * STEREO )
|
||||
{
|
||||
end_pos -= WIDTH * STEREO;
|
||||
do
|
||||
{
|
||||
count++;
|
||||
remain--;
|
||||
in += (skip * STEREO) & STEREO;
|
||||
skip >>= 1;
|
||||
in += step;
|
||||
|
||||
if ( !remain )
|
||||
{
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
}
|
||||
while ( in <= end_pos );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int Fir_Resampler_initialize( int new_size )
|
||||
{
|
||||
res = 1;
|
||||
skip_bits = 0;
|
||||
imp_phase = 0;
|
||||
step = STEREO;
|
||||
ratio = 1.0;
|
||||
buffer = (sample_t *) realloc( buffer, (new_size + WRITE_OFFSET) * sizeof (sample_t) );
|
||||
write_pos = 0;
|
||||
if ( !buffer ) return 0;
|
||||
buffer_size = new_size + WRITE_OFFSET;
|
||||
Fir_Resampler_clear();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Fir_Resampler_shutdown( void )
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
buffer = 0;
|
||||
buffer_size = 0;
|
||||
write_pos = 0;
|
||||
}
|
||||
|
||||
void Fir_Resampler_clear()
|
||||
{
|
||||
imp_phase = 0;
|
||||
if ( buffer_size )
|
||||
{
|
||||
write_pos = &buffer [WRITE_OFFSET];
|
||||
memset( buffer, 0, buffer_size * sizeof (sample_t) );
|
||||
}
|
||||
}
|
||||
|
||||
double Fir_Resampler_time_ratio( double new_factor, double rolloff )
|
||||
{
|
||||
ratio = new_factor;
|
||||
|
||||
int i, r;
|
||||
double nearest, error;
|
||||
double fstep = 0.0;
|
||||
double least_error = 2;
|
||||
double pos = 0.0;
|
||||
res = -1;
|
||||
|
||||
#ifdef NGC
|
||||
u32 level = IRQ_Disable();
|
||||
#endif
|
||||
|
||||
for ( r = 1; r <= MAX_RES; r++ )
|
||||
{
|
||||
pos += ratio;
|
||||
nearest = floor( pos + 0.5 );
|
||||
error = fabs( pos - nearest );
|
||||
if ( error < least_error )
|
||||
{
|
||||
res = r;
|
||||
fstep = nearest / res;
|
||||
least_error = error;
|
||||
}
|
||||
}
|
||||
|
||||
skip_bits = 0;
|
||||
|
||||
step = STEREO * (int) floor( fstep );
|
||||
|
||||
ratio = fstep;
|
||||
fstep = fmod( fstep, 1.0 );
|
||||
|
||||
double filter = (ratio < 1.0) ? 1.0 : 1.0 / ratio;
|
||||
pos = 0.0;
|
||||
input_per_cycle = 0;
|
||||
|
||||
memset(impulses, 0, MAX_RES*WIDTH*sizeof(sample_t));
|
||||
|
||||
for ( i = 0; i < res; i++ )
|
||||
{
|
||||
gen_sinc( rolloff, (int) (WIDTH * filter + 1) & ~1, pos, filter,
|
||||
(double) (0x7FFF * GAIN * filter),
|
||||
(int) WIDTH, impulses[i] );
|
||||
|
||||
pos += fstep;
|
||||
input_per_cycle += step;
|
||||
if ( pos >= 0.9999999 )
|
||||
{
|
||||
pos -= 1.0;
|
||||
skip_bits |= 1 << i;
|
||||
input_per_cycle++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NGC
|
||||
IRQ_Restore(level);
|
||||
#endif
|
||||
|
||||
Fir_Resampler_clear();
|
||||
|
||||
return ratio;
|
||||
}
|
||||
|
||||
/* Current ratio */
|
||||
double Fir_Resampler_ratio( void )
|
||||
{
|
||||
return ratio;
|
||||
}
|
||||
|
||||
/* Number of input samples that can be written */
|
||||
int Fir_Resampler_max_write( void )
|
||||
{
|
||||
return buffer + buffer_size - write_pos;
|
||||
}
|
||||
|
||||
/* Pointer to place to write input samples */
|
||||
sample_t* Fir_Resampler_buffer( void )
|
||||
{
|
||||
return write_pos;
|
||||
}
|
||||
|
||||
/* Number of input samples in buffer */
|
||||
int Fir_Resampler_written( void )
|
||||
{
|
||||
return write_pos - &buffer [WRITE_OFFSET];
|
||||
}
|
||||
|
||||
/* Number of output samples available */
|
||||
/*int Fir_Resampler_avail( void )
|
||||
{
|
||||
return available( write_pos - &buffer [WIDTH * STEREO] );
|
||||
}*/
|
||||
|
||||
void Fir_Resampler_write( long count )
|
||||
{
|
||||
write_pos += count;
|
||||
}
|
||||
|
||||
int Fir_Resampler_read( sample_t* out, long count )
|
||||
{
|
||||
sample_t* out_ = out;
|
||||
sample_t* in = buffer;
|
||||
sample_t* end_pos = write_pos;
|
||||
unsigned long skip = skip_bits >> imp_phase;
|
||||
sample_t const* imp = impulses [imp_phase];
|
||||
int remain = res - imp_phase;
|
||||
int n;
|
||||
int pt0,pt1;
|
||||
sample_t* i;
|
||||
long l,r;
|
||||
|
||||
if ( end_pos - in >= WIDTH * STEREO )
|
||||
{
|
||||
end_pos -= WIDTH * STEREO;
|
||||
do
|
||||
{
|
||||
count--;
|
||||
|
||||
if ( count < 0 )
|
||||
break;
|
||||
|
||||
/* accumulate in extended precision */
|
||||
l = 0;
|
||||
r = 0;
|
||||
|
||||
i = in;
|
||||
|
||||
for ( n = WIDTH / 2; n; --n )
|
||||
{
|
||||
pt0 = imp [0];
|
||||
l += pt0 * i [0];
|
||||
r += pt0 * i [1];
|
||||
pt1 = imp [1];
|
||||
imp += 2;
|
||||
l += pt1 * i [2];
|
||||
r += pt1 * i [3];
|
||||
i += 4;
|
||||
}
|
||||
|
||||
remain--;
|
||||
|
||||
l >>= 15;
|
||||
r >>= 15;
|
||||
|
||||
in += (skip * STEREO) & STEREO;
|
||||
skip >>= 1;
|
||||
in += step;
|
||||
|
||||
if ( !remain )
|
||||
{
|
||||
imp = impulses [0];
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
|
||||
*out++ = (sample_t) l;
|
||||
*out++ = (sample_t) r;
|
||||
}
|
||||
while ( in <= end_pos );
|
||||
}
|
||||
|
||||
imp_phase = res - remain;
|
||||
|
||||
int left = write_pos - in;
|
||||
write_pos = &buffer [left];
|
||||
memmove( buffer, in, left * sizeof *in );
|
||||
|
||||
return out - out_;
|
||||
}
|
||||
|
||||
/* fixed (Eke_Eke) */
|
||||
int Fir_Resampler_input_needed( long output_count )
|
||||
{
|
||||
long input_count = 0;
|
||||
|
||||
unsigned long skip = skip_bits >> imp_phase;
|
||||
int remain = res - imp_phase;
|
||||
while ( (output_count) > 0 )
|
||||
{
|
||||
input_count += step + (skip & 1) * STEREO;
|
||||
skip >>= 1;
|
||||
if ( !--remain )
|
||||
{
|
||||
skip = skip_bits;
|
||||
remain = res;
|
||||
}
|
||||
output_count --;
|
||||
}
|
||||
|
||||
long input_extra = input_count - (write_pos - &buffer [WRITE_OFFSET]);
|
||||
if ( input_extra < 0 )
|
||||
input_extra = 0;
|
||||
return (input_extra >> 1);
|
||||
}
|
||||
|
||||
int Fir_Resampler_skip_input( long count )
|
||||
{
|
||||
int remain = write_pos - buffer;
|
||||
int max_count = remain - WIDTH * STEREO;
|
||||
if ( count > max_count )
|
||||
count = max_count;
|
||||
|
||||
remain -= count;
|
||||
write_pos = &buffer [remain];
|
||||
memmove( buffer, &buffer [count], remain * sizeof buffer [0] );
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -1,29 +1,29 @@
|
||||
/* Finite impulse response (FIR) resampler with adjustable FIR size */
|
||||
|
||||
/* Game_Music_Emu 0.5.2 */
|
||||
#ifndef FIR_RESAMPLER_H
|
||||
#define FIR_RESAMPLER_H
|
||||
|
||||
#define STEREO 2
|
||||
#define MAX_RES 32
|
||||
#define WIDTH 16
|
||||
#define WRITE_OFFSET (WIDTH * STEREO) - STEREO
|
||||
#define GAIN 1.0
|
||||
|
||||
typedef signed long int sample_t;
|
||||
|
||||
extern int Fir_Resampler_initialize( int new_size );
|
||||
extern void Fir_Resampler_shutdown( void );
|
||||
extern void Fir_Resampler_clear( void );
|
||||
extern double Fir_Resampler_time_ratio( double new_factor, double rolloff );
|
||||
extern double Fir_Resampler_ratio( void );
|
||||
extern int Fir_Resampler_max_write( void );
|
||||
extern sample_t* Fir_Resampler_buffer( void );
|
||||
extern int Fir_Resampler_written( void );
|
||||
extern int Fir_Resampler_avail( void );
|
||||
extern void Fir_Resampler_write( long count );
|
||||
extern int Fir_Resampler_read( sample_t* out, long count );
|
||||
extern int Fir_Resampler_input_needed( long output_count );
|
||||
extern int Fir_Resampler_skip_input( long count );
|
||||
|
||||
#endif
|
||||
/* Finite impulse response (FIR) resampler with adjustable FIR size */
|
||||
|
||||
/* Game_Music_Emu 0.5.2 */
|
||||
#ifndef FIR_RESAMPLER_H
|
||||
#define FIR_RESAMPLER_H
|
||||
|
||||
#define STEREO 2
|
||||
#define MAX_RES 32
|
||||
#define WIDTH 16
|
||||
#define WRITE_OFFSET (WIDTH * STEREO) - STEREO
|
||||
#define GAIN 1.0
|
||||
|
||||
typedef signed long int sample_t;
|
||||
|
||||
extern int Fir_Resampler_initialize( int new_size );
|
||||
extern void Fir_Resampler_shutdown( void );
|
||||
extern void Fir_Resampler_clear( void );
|
||||
extern double Fir_Resampler_time_ratio( double new_factor, double rolloff );
|
||||
extern double Fir_Resampler_ratio( void );
|
||||
extern int Fir_Resampler_max_write( void );
|
||||
extern sample_t* Fir_Resampler_buffer( void );
|
||||
extern int Fir_Resampler_written( void );
|
||||
extern int Fir_Resampler_avail( void );
|
||||
extern void Fir_Resampler_write( long count );
|
||||
extern int Fir_Resampler_read( sample_t* out, long count );
|
||||
extern int Fir_Resampler_input_needed( long output_count );
|
||||
extern int Fir_Resampler_skip_input( long count );
|
||||
|
||||
#endif
|
||||
|
@ -1,163 +1,155 @@
|
||||
/* http://www.slack.net/~ant/ */
|
||||
|
||||
#include "blip.h"
|
||||
|
||||
//#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
enum { buf_extra = 2 }; /* extra samples to save past end */
|
||||
enum { time_bits = 16 }; /* bits in fraction of fixed-point sample counts */
|
||||
enum { time_unit = 1 << time_bits };
|
||||
enum { phase_bits = 15 }; /* bits in fraction of deltas in buffer */
|
||||
enum { phase_count = 1 << phase_bits };
|
||||
enum { phase_shift = time_bits - phase_bits };
|
||||
|
||||
typedef int buf_t; /* type of element in delta buffer */
|
||||
|
||||
struct blip_buffer_t
|
||||
{
|
||||
int factor; /* clocks to samples conversion factor */
|
||||
int offset; /* fractional position of clock 0 in delta buffer */
|
||||
int amp; /* current output amplitude (sum of all deltas up to now) */
|
||||
int size; /* size of delta buffer */
|
||||
buf_t buf [65536]; /* delta buffer, only size elements actually allocated */
|
||||
};
|
||||
|
||||
blip_buffer_t* blip_alloc( double clock_rate, double sample_rate, int size )
|
||||
{
|
||||
/* Allocate space for structure and delta buffer */
|
||||
blip_buffer_t* s = (blip_buffer_t*) malloc(
|
||||
offsetof (blip_buffer_t, buf) + (size + buf_extra) * sizeof (buf_t) );
|
||||
if ( s != NULL )
|
||||
{
|
||||
/* Calculate output:input ratio and convert to fixed-point */
|
||||
double ratio = sample_rate / clock_rate;
|
||||
s->factor = (int) (ratio * time_unit + 0.5);
|
||||
|
||||
s->size = size;
|
||||
blip_clear( s );
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void blip_free( blip_buffer_t* s )
|
||||
{
|
||||
free( s );
|
||||
}
|
||||
|
||||
void blip_clear( blip_buffer_t* s )
|
||||
{
|
||||
s->offset = 0;
|
||||
s->amp = 0;
|
||||
memset( s->buf, 0, (s->size + buf_extra) * sizeof (buf_t) );
|
||||
}
|
||||
|
||||
void blip_add( blip_buffer_t* s, int clocks, int delta )
|
||||
{
|
||||
/* Convert to fixed-point time in terms of output samples */
|
||||
int fixed_time = clocks * s->factor + s->offset;
|
||||
|
||||
/* Extract whole and fractional parts */
|
||||
int index = fixed_time >> time_bits; /* whole */
|
||||
int phase = fixed_time >> phase_shift & (phase_count - 1); /* fraction */
|
||||
|
||||
/* Split delta between first and second samples */
|
||||
int second = delta * phase;
|
||||
int first = delta * phase_count - second;
|
||||
|
||||
/* Be sure index is within buffer */
|
||||
//assert( index >= 0 && index+1 < s->size + buf_extra );
|
||||
|
||||
/* Add deltas to buffer */
|
||||
s->buf [index ] += first;
|
||||
s->buf [index+1] += second;
|
||||
}
|
||||
|
||||
int blip_clocks_needed( const blip_buffer_t* s, int samples )
|
||||
{
|
||||
int fixed_needed;
|
||||
if ( samples > s->size )
|
||||
samples = s->size;
|
||||
|
||||
/* Fixed-point number of samples needed in addition to those in buffer */
|
||||
fixed_needed = samples * time_unit - s->offset;
|
||||
|
||||
/* If more are needed, convert to clocks and round up */
|
||||
return (fixed_needed <= 0) ? 0 : (fixed_needed - 1) / s->factor + 1;
|
||||
}
|
||||
|
||||
void blip_end_frame( blip_buffer_t* s, int clocks )
|
||||
{
|
||||
s->offset += clocks * s->factor;
|
||||
|
||||
/* Ensure time wasn't past end of buffer */
|
||||
//assert( blip_samples_avail( s ) <= s->size );
|
||||
}
|
||||
|
||||
int blip_samples_avail( const blip_buffer_t* s )
|
||||
{
|
||||
return s->offset >> time_bits;
|
||||
}
|
||||
|
||||
/* Removes n samples from buffer */
|
||||
static void remove_samples( blip_buffer_t* s, int n )
|
||||
{
|
||||
int remain = blip_samples_avail( s ) + buf_extra - n;
|
||||
|
||||
s->offset -= n * time_unit;
|
||||
//assert( s->offset >= 0 );
|
||||
|
||||
/* Copy remaining samples to beginning of buffer and clear the rest */
|
||||
memmove( s->buf, &s->buf [n], remain * sizeof (buf_t) );
|
||||
memset( &s->buf [remain], 0, n * sizeof (buf_t) );
|
||||
}
|
||||
|
||||
int blip_read_samples( blip_buffer_t* s, short out [], int count, int stereo )
|
||||
{
|
||||
/* can't read more than available */
|
||||
int avail = blip_samples_avail( s );
|
||||
if ( count > avail )
|
||||
count = avail;
|
||||
|
||||
if ( count )
|
||||
{
|
||||
/* Sum deltas and write out */
|
||||
int i;
|
||||
for ( i = 0; i < count; ++i )
|
||||
{
|
||||
int sample;
|
||||
|
||||
/* Apply slight high-pass filter */
|
||||
s->amp -= s->amp >> 9;
|
||||
|
||||
/* Add next delta */
|
||||
s->amp += s->buf [i];
|
||||
|
||||
/* Calculate output sample */
|
||||
sample = s->amp >> phase_bits;
|
||||
|
||||
/* Keep within 16-bit sample range */
|
||||
if ( sample < -32768 ) sample = -32768;
|
||||
if ( sample > +32767 ) sample = +32767;
|
||||
|
||||
out [i << stereo] = sample;
|
||||
}
|
||||
|
||||
remove_samples( s, count );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
/* http://www.slack.net/~ant/ */
|
||||
|
||||
#include "blip.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
enum { buf_extra = 2 }; /* extra samples to save past end */
|
||||
enum { time_bits = 16 }; /* bits in fraction of fixed-point sample counts */
|
||||
enum { time_unit = 1 << time_bits };
|
||||
enum { phase_bits = 15 }; /* bits in fraction of deltas in buffer */
|
||||
enum { phase_count = 1 << phase_bits };
|
||||
enum { phase_shift = time_bits - phase_bits };
|
||||
|
||||
typedef int buf_t; /* type of element in delta buffer */
|
||||
|
||||
struct blip_buffer_t
|
||||
{
|
||||
int factor; /* clocks to samples conversion factor */
|
||||
int offset; /* fractional position of clock 0 in delta buffer */
|
||||
int amp; /* current output amplitude (sum of all deltas up to now) */
|
||||
int size; /* size of delta buffer */
|
||||
buf_t buf [65536]; /* delta buffer, only size elements actually allocated */
|
||||
};
|
||||
|
||||
blip_buffer_t* blip_alloc( double clock_rate, double sample_rate, int size )
|
||||
{
|
||||
/* Allocate space for structure and delta buffer */
|
||||
blip_buffer_t* s = (blip_buffer_t*) malloc(
|
||||
offsetof (blip_buffer_t, buf) + (size + buf_extra) * sizeof (buf_t) );
|
||||
if ( s != NULL )
|
||||
{
|
||||
/* Calculate output:input ratio and convert to fixed-point */
|
||||
double ratio = sample_rate / clock_rate;
|
||||
s->factor = (int) (ratio * time_unit + 0.5);
|
||||
|
||||
s->size = size;
|
||||
blip_clear( s );
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void blip_free( blip_buffer_t* s )
|
||||
{
|
||||
free( s );
|
||||
}
|
||||
|
||||
void blip_clear( blip_buffer_t* s )
|
||||
{
|
||||
s->offset = 0;
|
||||
s->amp = 0;
|
||||
memset( s->buf, 0, (s->size + buf_extra) * sizeof (buf_t) );
|
||||
}
|
||||
|
||||
void blip_add( blip_buffer_t* s, int clocks, int delta )
|
||||
{
|
||||
/* Convert to fixed-point time in terms of output samples */
|
||||
int fixed_time = clocks * s->factor + s->offset;
|
||||
|
||||
/* Extract whole and fractional parts */
|
||||
int index = fixed_time >> time_bits; /* whole */
|
||||
int phase = fixed_time >> phase_shift & (phase_count - 1); /* fraction */
|
||||
|
||||
/* Split delta between first and second samples */
|
||||
int second = delta * phase;
|
||||
int first = delta * phase_count - second;
|
||||
|
||||
/* Add deltas to buffer */
|
||||
s->buf [index ] += first;
|
||||
s->buf [index+1] += second;
|
||||
}
|
||||
|
||||
int blip_clocks_needed( const blip_buffer_t* s, int samples )
|
||||
{
|
||||
int fixed_needed;
|
||||
if ( samples > s->size )
|
||||
samples = s->size;
|
||||
|
||||
/* Fixed-point number of samples needed in addition to those in buffer */
|
||||
fixed_needed = samples * time_unit - s->offset;
|
||||
|
||||
/* If more are needed, convert to clocks and round up */
|
||||
return (fixed_needed <= 0) ? 0 : (fixed_needed - 1) / s->factor + 1;
|
||||
}
|
||||
|
||||
void blip_end_frame( blip_buffer_t* s, int clocks )
|
||||
{
|
||||
s->offset += clocks * s->factor;
|
||||
}
|
||||
|
||||
int blip_samples_avail( const blip_buffer_t* s )
|
||||
{
|
||||
return s->offset >> time_bits;
|
||||
}
|
||||
|
||||
/* Removes n samples from buffer */
|
||||
static void remove_samples( blip_buffer_t* s, int n )
|
||||
{
|
||||
int remain = blip_samples_avail( s ) + buf_extra - n;
|
||||
|
||||
s->offset -= n * time_unit;
|
||||
|
||||
/* Copy remaining samples to beginning of buffer and clear the rest */
|
||||
memmove( s->buf, &s->buf [n], remain * sizeof (buf_t) );
|
||||
memset( &s->buf [remain], 0, n * sizeof (buf_t) );
|
||||
}
|
||||
|
||||
int blip_read_samples( blip_buffer_t* s, short out [], int count, int stereo )
|
||||
{
|
||||
/* can't read more than available */
|
||||
int avail = blip_samples_avail( s );
|
||||
if ( count > avail )
|
||||
count = avail;
|
||||
|
||||
if ( count )
|
||||
{
|
||||
/* Sum deltas and write out */
|
||||
int i;
|
||||
for ( i = 0; i < count; ++i )
|
||||
{
|
||||
int sample;
|
||||
|
||||
/* Apply slight high-pass filter */
|
||||
s->amp -= s->amp >> 9;
|
||||
|
||||
/* Add next delta */
|
||||
s->amp += s->buf [i];
|
||||
|
||||
/* Calculate output sample */
|
||||
sample = s->amp >> phase_bits;
|
||||
|
||||
/* Keep within 16-bit sample range */
|
||||
if ( sample < -32768 ) sample = -32768;
|
||||
if ( sample > +32767 ) sample = +32767;
|
||||
|
||||
out [i << stereo] = sample;
|
||||
}
|
||||
|
||||
remove_samples( s, count );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -1,51 +1,51 @@
|
||||
/* Fast sound synthesis buffer for use in real-time emulators of electronic
|
||||
sound generator chips like those in early video game consoles. Uses linear
|
||||
interpolation. Higher-quality versions are available that use sinc-based
|
||||
band-limited synthesis. */
|
||||
|
||||
#ifndef BLIP_H
|
||||
#define BLIP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Creates a new blip_buffer with specified input clock rate, output
|
||||
sample rate, and size (in samples), or returns NULL if out of memory. */
|
||||
typedef struct blip_buffer_t blip_buffer_t;
|
||||
blip_buffer_t* blip_alloc( double clock_rate, double sample_rate, int size );
|
||||
|
||||
/* Frees memory used by a blip_buffer. No effect if NULL is passed. */
|
||||
void blip_free( blip_buffer_t* );
|
||||
|
||||
/* Removes all samples and clears buffer. */
|
||||
void blip_clear( blip_buffer_t* );
|
||||
|
||||
/* Adds an amplitude transition of delta at specified time in source clocks.
|
||||
Delta can be negative. */
|
||||
void blip_add( blip_buffer_t*, int time, int delta );
|
||||
|
||||
/* Number of additional clocks needed until n samples will be available.
|
||||
If buffer cannot even hold n samples, returns number of clocks until buffer
|
||||
becomes full. */
|
||||
int blip_clocks_needed( const blip_buffer_t*, int samples_needed );
|
||||
|
||||
/* Ends current time frame of specified duration and make its samples available
|
||||
(along with any still-unread samples) for reading with read_samples(), then
|
||||
begins a new time frame at the end of the current frame. */
|
||||
void blip_end_frame( blip_buffer_t*, int duration );
|
||||
|
||||
/* Number of samples available for reading with read(). */
|
||||
int blip_samples_avail( const blip_buffer_t* );
|
||||
|
||||
/* Reads at most n samples out of buffer into out, removing them from from
|
||||
the buffer. Returns number of samples actually read and removed. If stereo is
|
||||
true, increments 'out' one extra time after writing each sample, to allow
|
||||
easy interleving of two channels into a stereo output buffer. */
|
||||
int blip_read_samples( blip_buffer_t*, short out [], int n, int stereo );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Fast sound synthesis buffer for use in real-time emulators of electronic
|
||||
sound generator chips like those in early video game consoles. Uses linear
|
||||
interpolation. Higher-quality versions are available that use sinc-based
|
||||
band-limited synthesis. */
|
||||
|
||||
#ifndef BLIP_H
|
||||
#define BLIP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Creates a new blip_buffer with specified input clock rate, output
|
||||
sample rate, and size (in samples), or returns NULL if out of memory. */
|
||||
typedef struct blip_buffer_t blip_buffer_t;
|
||||
blip_buffer_t* blip_alloc( double clock_rate, double sample_rate, int size );
|
||||
|
||||
/* Frees memory used by a blip_buffer. No effect if NULL is passed. */
|
||||
void blip_free( blip_buffer_t* );
|
||||
|
||||
/* Removes all samples and clears buffer. */
|
||||
void blip_clear( blip_buffer_t* );
|
||||
|
||||
/* Adds an amplitude transition of delta at specified time in source clocks.
|
||||
Delta can be negative. */
|
||||
void blip_add( blip_buffer_t*, int time, int delta );
|
||||
|
||||
/* Number of additional clocks needed until n samples will be available.
|
||||
If buffer cannot even hold n samples, returns number of clocks until buffer
|
||||
becomes full. */
|
||||
int blip_clocks_needed( const blip_buffer_t*, int samples_needed );
|
||||
|
||||
/* Ends current time frame of specified duration and make its samples available
|
||||
(along with any still-unread samples) for reading with read_samples(), then
|
||||
begins a new time frame at the end of the current frame. */
|
||||
void blip_end_frame( blip_buffer_t*, int duration );
|
||||
|
||||
/* Number of samples available for reading with read(). */
|
||||
int blip_samples_avail( const blip_buffer_t* );
|
||||
|
||||
/* Reads at most n samples out of buffer into out, removing them from from
|
||||
the buffer. Returns number of samples actually read and removed. If stereo is
|
||||
true, increments 'out' one extra time after writing each sample, to allow
|
||||
easy interleving of two channels into a stereo output buffer. */
|
||||
int blip_read_samples( blip_buffer_t*, short out [], int n, int stereo );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,131 +1,131 @@
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// 3 Band EQ :)
|
||||
//
|
||||
// EQ.C - Main Source file for 3 band EQ
|
||||
//
|
||||
// (c) Neil C / Etanza Systems / 2K6
|
||||
//
|
||||
// Shouts / Loves / Moans = etanza at lycos dot co dot uk
|
||||
//
|
||||
// This work is hereby placed in the public domain for all purposes, including
|
||||
// use in commercial applications.
|
||||
//
|
||||
// The author assumes NO RESPONSIBILITY for any problems caused by the use of
|
||||
// this software.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// NOTES :
|
||||
//
|
||||
// - Original filter code by Paul Kellet (musicdsp.pdf)
|
||||
//
|
||||
// - Uses 4 first order filters in series, should give 24dB per octave
|
||||
//
|
||||
// - Now with P4 Denormal fix :)
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// ----------
|
||||
//| Includes |
|
||||
// ----------
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "eq.h"
|
||||
|
||||
|
||||
// -----------
|
||||
//| Constants |
|
||||
// -----------
|
||||
|
||||
static double vsa = (1.0 / 4294967295.0); // Very small amount (Denormal Fix)
|
||||
|
||||
|
||||
// ---------------
|
||||
//| Initialise EQ |
|
||||
// ---------------
|
||||
|
||||
// Recommended frequencies are ...
|
||||
//
|
||||
// lowfreq = 880 Hz
|
||||
// highfreq = 5000 Hz
|
||||
//
|
||||
// Set mixfreq to whatever rate your system is using (eg 48Khz)
|
||||
|
||||
void init_3band_state(EQSTATE * es, int lowfreq, int highfreq, int mixfreq)
|
||||
{
|
||||
// Clear state
|
||||
|
||||
memset(es, 0, sizeof(EQSTATE));
|
||||
|
||||
// Set Low/Mid/High gains to unity
|
||||
|
||||
es->lg = 1.0;
|
||||
es->mg = 1.0;
|
||||
es->hg = 1.0;
|
||||
|
||||
// Calculate filter cutoff frequencies
|
||||
|
||||
es->lf = 2 * sin(M_PI * ((double) lowfreq / (double) mixfreq));
|
||||
es->hf = 2 * sin(M_PI * ((double) highfreq / (double) mixfreq));
|
||||
}
|
||||
|
||||
|
||||
// ---------------
|
||||
//| EQ one sample |
|
||||
// ---------------
|
||||
|
||||
// - sample can be any range you like :)
|
||||
//
|
||||
// Note that the output will depend on the gain settings for each band
|
||||
// (especially the bass) so may require clipping before output, but you
|
||||
// knew that anyway :)
|
||||
|
||||
double do_3band(EQSTATE * es, int sample)
|
||||
{
|
||||
// Locals
|
||||
|
||||
double l, m, h; // Low / Mid / High - Sample Values
|
||||
|
||||
// Filter #1 (lowpass)
|
||||
|
||||
es->f1p0 += (es->lf * ((double) sample - es->f1p0)) + vsa;
|
||||
es->f1p1 += (es->lf * (es->f1p0 - es->f1p1));
|
||||
es->f1p2 += (es->lf * (es->f1p1 - es->f1p2));
|
||||
es->f1p3 += (es->lf * (es->f1p2 - es->f1p3));
|
||||
|
||||
l = es->f1p3;
|
||||
|
||||
// Filter #2 (highpass)
|
||||
|
||||
es->f2p0 += (es->hf * ((double) sample - es->f2p0)) + vsa;
|
||||
es->f2p1 += (es->hf * (es->f2p0 - es->f2p1));
|
||||
es->f2p2 += (es->hf * (es->f2p1 - es->f2p2));
|
||||
es->f2p3 += (es->hf * (es->f2p2 - es->f2p3));
|
||||
|
||||
h = es->sdm3 - es->f2p3;
|
||||
|
||||
// Calculate midrange (signal - (low + high))
|
||||
|
||||
//m = es->sdm3 - (h + l);
|
||||
// fix from http://www.musicdsp.org/showArchiveComment.php?ArchiveID=236 ?
|
||||
m = sample - (h + l);
|
||||
|
||||
// Scale, Combine and store
|
||||
|
||||
l *= es->lg;
|
||||
m *= es->mg;
|
||||
h *= es->hg;
|
||||
|
||||
// Shuffle history buffer
|
||||
|
||||
es->sdm3 = es->sdm2;
|
||||
es->sdm2 = es->sdm1;
|
||||
es->sdm1 = sample;
|
||||
|
||||
// Return result
|
||||
|
||||
return (int) (l + m + h);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// 3 Band EQ :)
|
||||
//
|
||||
// EQ.C - Main Source file for 3 band EQ
|
||||
//
|
||||
// (c) Neil C / Etanza Systems / 2K6
|
||||
//
|
||||
// Shouts / Loves / Moans = etanza at lycos dot co dot uk
|
||||
//
|
||||
// This work is hereby placed in the public domain for all purposes, including
|
||||
// use in commercial applications.
|
||||
//
|
||||
// The author assumes NO RESPONSIBILITY for any problems caused by the use of
|
||||
// this software.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// NOTES :
|
||||
//
|
||||
// - Original filter code by Paul Kellet (musicdsp.pdf)
|
||||
//
|
||||
// - Uses 4 first order filters in series, should give 24dB per octave
|
||||
//
|
||||
// - Now with P4 Denormal fix :)
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// ----------
|
||||
//| Includes |
|
||||
// ----------
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "eq.h"
|
||||
|
||||
|
||||
// -----------
|
||||
//| Constants |
|
||||
// -----------
|
||||
|
||||
static double vsa = (1.0 / 4294967295.0); // Very small amount (Denormal Fix)
|
||||
|
||||
|
||||
// ---------------
|
||||
//| Initialise EQ |
|
||||
// ---------------
|
||||
|
||||
// Recommended frequencies are ...
|
||||
//
|
||||
// lowfreq = 880 Hz
|
||||
// highfreq = 5000 Hz
|
||||
//
|
||||
// Set mixfreq to whatever rate your system is using (eg 48Khz)
|
||||
|
||||
void init_3band_state(EQSTATE * es, int lowfreq, int highfreq, int mixfreq)
|
||||
{
|
||||
// Clear state
|
||||
|
||||
memset(es, 0, sizeof(EQSTATE));
|
||||
|
||||
// Set Low/Mid/High gains to unity
|
||||
|
||||
es->lg = 1.0;
|
||||
es->mg = 1.0;
|
||||
es->hg = 1.0;
|
||||
|
||||
// Calculate filter cutoff frequencies
|
||||
|
||||
es->lf = 2 * sin(M_PI * ((double) lowfreq / (double) mixfreq));
|
||||
es->hf = 2 * sin(M_PI * ((double) highfreq / (double) mixfreq));
|
||||
}
|
||||
|
||||
|
||||
// ---------------
|
||||
//| EQ one sample |
|
||||
// ---------------
|
||||
|
||||
// - sample can be any range you like :)
|
||||
//
|
||||
// Note that the output will depend on the gain settings for each band
|
||||
// (especially the bass) so may require clipping before output, but you
|
||||
// knew that anyway :)
|
||||
|
||||
double do_3band(EQSTATE * es, int sample)
|
||||
{
|
||||
// Locals
|
||||
|
||||
double l, m, h; // Low / Mid / High - Sample Values
|
||||
|
||||
// Filter #1 (lowpass)
|
||||
|
||||
es->f1p0 += (es->lf * ((double) sample - es->f1p0)) + vsa;
|
||||
es->f1p1 += (es->lf * (es->f1p0 - es->f1p1));
|
||||
es->f1p2 += (es->lf * (es->f1p1 - es->f1p2));
|
||||
es->f1p3 += (es->lf * (es->f1p2 - es->f1p3));
|
||||
|
||||
l = es->f1p3;
|
||||
|
||||
// Filter #2 (highpass)
|
||||
|
||||
es->f2p0 += (es->hf * ((double) sample - es->f2p0)) + vsa;
|
||||
es->f2p1 += (es->hf * (es->f2p0 - es->f2p1));
|
||||
es->f2p2 += (es->hf * (es->f2p1 - es->f2p2));
|
||||
es->f2p3 += (es->hf * (es->f2p2 - es->f2p3));
|
||||
|
||||
h = es->sdm3 - es->f2p3;
|
||||
|
||||
// Calculate midrange (signal - (low + high))
|
||||
|
||||
//m = es->sdm3 - (h + l);
|
||||
// fix from http://www.musicdsp.org/showArchiveComment.php?ArchiveID=236 ?
|
||||
m = sample - (h + l);
|
||||
|
||||
// Scale, Combine and store
|
||||
|
||||
l *= es->lg;
|
||||
m *= es->mg;
|
||||
h *= es->hg;
|
||||
|
||||
// Shuffle history buffer
|
||||
|
||||
es->sdm3 = es->sdm2;
|
||||
es->sdm2 = es->sdm1;
|
||||
es->sdm1 = sample;
|
||||
|
||||
// Return result
|
||||
|
||||
return (int) (l + m + h);
|
||||
}
|
||||
|
@ -1,67 +1,67 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 3 Band EQ :)
|
||||
//
|
||||
// EQ.H - Header file for 3 band EQ
|
||||
//
|
||||
// (c) Neil C / Etanza Systems / 2K6
|
||||
//
|
||||
// Shouts / Loves / Moans = etanza at lycos dot co dot uk
|
||||
//
|
||||
// This work is hereby placed in the public domain for all purposes, including
|
||||
// use in commercial applications.
|
||||
//
|
||||
// The author assumes NO RESPONSIBILITY for any problems caused by the use of
|
||||
// this software.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __EQ3BAND__
|
||||
#define __EQ3BAND__
|
||||
|
||||
// ------------
|
||||
//| Structures |
|
||||
// ------------
|
||||
|
||||
typedef struct {
|
||||
// Filter #1 (Low band)
|
||||
|
||||
double lf; // Frequency
|
||||
double f1p0; // Poles ...
|
||||
double f1p1;
|
||||
double f1p2;
|
||||
double f1p3;
|
||||
|
||||
// Filter #2 (High band)
|
||||
|
||||
double hf; // Frequency
|
||||
double f2p0; // Poles ...
|
||||
double f2p1;
|
||||
double f2p2;
|
||||
double f2p3;
|
||||
|
||||
// Sample history buffer
|
||||
|
||||
double sdm1; // Sample data minus 1
|
||||
double sdm2; // 2
|
||||
double sdm3; // 3
|
||||
|
||||
// Gain Controls
|
||||
|
||||
double lg; // low gain
|
||||
double mg; // mid gain
|
||||
double hg; // high gain
|
||||
|
||||
} EQSTATE;
|
||||
|
||||
|
||||
// ---------
|
||||
//| Exports |
|
||||
// ---------
|
||||
|
||||
extern void init_3band_state(EQSTATE * es, int lowfreq, int highfreq,
|
||||
int mixfreq);
|
||||
extern double do_3band(EQSTATE * es, int sample);
|
||||
|
||||
|
||||
#endif // #ifndef __EQ3BAND__
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 3 Band EQ :)
|
||||
//
|
||||
// EQ.H - Header file for 3 band EQ
|
||||
//
|
||||
// (c) Neil C / Etanza Systems / 2K6
|
||||
//
|
||||
// Shouts / Loves / Moans = etanza at lycos dot co dot uk
|
||||
//
|
||||
// This work is hereby placed in the public domain for all purposes, including
|
||||
// use in commercial applications.
|
||||
//
|
||||
// The author assumes NO RESPONSIBILITY for any problems caused by the use of
|
||||
// this software.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __EQ3BAND__
|
||||
#define __EQ3BAND__
|
||||
|
||||
// ------------
|
||||
//| Structures |
|
||||
// ------------
|
||||
|
||||
typedef struct {
|
||||
// Filter #1 (Low band)
|
||||
|
||||
double lf; // Frequency
|
||||
double f1p0; // Poles ...
|
||||
double f1p1;
|
||||
double f1p2;
|
||||
double f1p3;
|
||||
|
||||
// Filter #2 (High band)
|
||||
|
||||
double hf; // Frequency
|
||||
double f2p0; // Poles ...
|
||||
double f2p1;
|
||||
double f2p2;
|
||||
double f2p3;
|
||||
|
||||
// Sample history buffer
|
||||
|
||||
double sdm1; // Sample data minus 1
|
||||
double sdm2; // 2
|
||||
double sdm3; // 3
|
||||
|
||||
// Gain Controls
|
||||
|
||||
double lg; // low gain
|
||||
double mg; // mid gain
|
||||
double hg; // high gain
|
||||
|
||||
} EQSTATE;
|
||||
|
||||
|
||||
// ---------
|
||||
//| Exports |
|
||||
// ---------
|
||||
|
||||
extern void init_3band_state(EQSTATE * es, int lowfreq, int highfreq,
|
||||
int mixfreq);
|
||||
extern double do_3band(EQSTATE * es, int sample);
|
||||
|
||||
|
||||
#endif // #ifndef __EQ3BAND__
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
SN76489 emulation
|
||||
by Maxim in 2001 and 2002
|
||||
converted from my original Delphi implementation
|
||||
@ -47,7 +47,7 @@
|
||||
/* SN76489 clone in Sega's VDP chips (315-5124, 315-5246, 315-5313, Game Gear) */
|
||||
#define FB_SEGAVDP 0x0009
|
||||
#define SRW_SEGAVDP 16
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Configuration */
|
||||
@ -81,19 +81,19 @@ static const int PSGVolumeValues[16] = {
|
||||
static struct blip_buffer_t* blip; /* delta resampler */
|
||||
|
||||
static SN76489_Context SN76489;
|
||||
|
||||
|
||||
void SN76489_Init(double PSGClockValue, int SamplingRate)
|
||||
{
|
||||
{
|
||||
SN76489_Shutdown();
|
||||
|
||||
/* SamplingRate*16 instead of PSGClockValue/16 since division would lose some
|
||||
precision. blip_alloc doesn't care about the absolute sampling rate, just the
|
||||
ratio to clock rate. */
|
||||
blip = blip_alloc(PSGClockValue, SamplingRate * 16.0, SamplingRate / 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SN76489_Reset()
|
||||
{
|
||||
{
|
||||
SN76489_Context *chip = &SN76489;
|
||||
int i;
|
||||
|
||||
@ -102,35 +102,35 @@ void SN76489_Reset()
|
||||
/* Initialise PSG state */
|
||||
chip->Registers[2*i] = 1; /* tone freq=1 */
|
||||
chip->Registers[2*i+1] = 0xf; /* vol=off */
|
||||
|
||||
|
||||
/* Set counters to 0 */
|
||||
chip->ToneFreqVals[i] = 0;
|
||||
|
||||
|
||||
/* Set flip-flops to 1 */
|
||||
chip->ToneFreqPos[i] = 1;
|
||||
|
||||
|
||||
/* Clear channels output */
|
||||
chip->Channels[i] = 0;
|
||||
|
||||
|
||||
/* Clear current amplitudes in delta buffer */
|
||||
chip->chan_amp[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
chip->LatchedRegister=0;
|
||||
|
||||
|
||||
/* Initialise noise generator */
|
||||
chip->NoiseShiftRegister=NoiseInitialState;
|
||||
chip->NoiseFreq = 0x10;
|
||||
|
||||
|
||||
/* Clear Blip delta buffer */
|
||||
if (blip) blip_clear(blip);
|
||||
}
|
||||
}
|
||||
|
||||
void SN76489_Shutdown(void)
|
||||
{
|
||||
{
|
||||
if (blip) blip_free(blip);
|
||||
blip = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SN76489_BoostNoise(int boost)
|
||||
{
|
||||
@ -139,7 +139,7 @@ void SN76489_BoostNoise(int boost)
|
||||
}
|
||||
|
||||
void SN76489_SetContext(uint8 *data)
|
||||
{
|
||||
{
|
||||
memcpy(&SN76489, data, sizeof(SN76489_Context));
|
||||
}
|
||||
|
||||
@ -335,4 +335,4 @@ void SN76489_Update(INT16 *buffer, int length)
|
||||
/* Read samples into output buffer */
|
||||
blip_end_frame(blip, clock_length);
|
||||
blip_read_samples(blip, buffer, length, 0);
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,13 @@
|
||||
/*
|
||||
SN76489 emulation
|
||||
by Maxim in 2001 and 2002
|
||||
converted from my original Delphi implementation
|
||||
|
||||
I'm a C newbie so I'm sure there are loads of stupid things
|
||||
in here which I'll come back to some day and redo
|
||||
|
||||
Includes:
|
||||
- Super-high quality tone channel "oversampling" by calculating fractional positions on transitions
|
||||
- Noise output pattern reverse engineered from actual SMS output
|
||||
- Volume levels taken from actual SMS output
|
||||
*/
|
||||
|
||||
#ifndef _SN76489_H_
|
||||
#define _SN76489_H_
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
extern void SN76489_Init(double PSGClockValue, int SamplingRate);
|
||||
extern void SN76489_Reset(void);
|
||||
extern void SN76489_Shutdown(void);
|
||||
@ -27,5 +19,5 @@ extern void SN76489_Write(int data);
|
||||
extern void SN76489_Update(INT16 *buffer, int length);
|
||||
extern void SN76489_BoostNoise(int boost);
|
||||
|
||||
#endif /* _SN76489_H_ */
|
||||
|
||||
#endif /* _SN76489_H_ */
|
||||
|
||||
|
@ -172,7 +172,8 @@ int sound_context_load(uint8 *state, char *version)
|
||||
int bufferptr = YM2612LoadContext(state, version);
|
||||
load_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
|
||||
|
||||
if (version[15] > 0x30)
|
||||
/* extended state (from 1.4.1 and above) */
|
||||
if ((version[11] > 0x31) || (version[13] > 0x34) || (version[15] > 0x30))
|
||||
{
|
||||
load_param(&fm_cycles_count,sizeof(fm_cycles_count));
|
||||
load_param(&psg_cycles_count,sizeof(psg_cycles_count));
|
||||
|
@ -1,28 +1,28 @@
|
||||
/*
|
||||
**
|
||||
** software implementation of Yamaha YM2612 FM sound generator (taken from M.A.M.E fm.c)
|
||||
** software implementation of Yamaha FM sound generator (YM2612/YM3438)
|
||||
**
|
||||
** Original code (MAME fm.c)
|
||||
**
|
||||
** Copyright (C) 2001, 2002, 2003 Jarek Burczynski (bujar at mame dot net)
|
||||
** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development
|
||||
**
|
||||
** Version 1.4 (final beta)
|
||||
**
|
||||
*/
|
||||
|
||||
/*
|
||||
** History:
|
||||
** Additional code & fixes by Eke-Eke for Genesis Plus GX
|
||||
**
|
||||
** 2006~2009 Eke-Eke (Genesis Plus GX):
|
||||
** Huge thanks to Nemesis, lot of those fixes came from his tests on Sega Genesis hardware
|
||||
** Huge thanks to Nemesis, most of those fixes came from his tests on Sega Genesis hardware
|
||||
** More informations at http://gendev.spritesmind.net/forum/viewtopic.php?t=386
|
||||
**
|
||||
** TODO:
|
||||
**
|
||||
** - core documentation
|
||||
** - BUSY flag support
|
||||
**
|
||||
** - better documentation
|
||||
** - BUSY flag emulation
|
||||
*/
|
||||
|
||||
/*
|
||||
** CHANGELOG:
|
||||
**
|
||||
** 2006~2011 Eke-Eke (Genesis Plus GX):
|
||||
** - removed unused multichip support
|
||||
** - added YM2612 Context external access functions
|
||||
** - fixed LFO implementation:
|
||||
@ -40,6 +40,7 @@
|
||||
** - implemented accurate CSM mode emulation
|
||||
** - implemented accurate SSG-EG emulation (Asterix, Beavis&Butthead, Bubba'n Stix & many other games)
|
||||
** - implemented accurate address/data ports behavior
|
||||
** - added preliminar support for DAC precision
|
||||
**
|
||||
**
|
||||
** 03-08-2003 Jarek Burczynski:
|
||||
@ -2213,8 +2214,8 @@ int YM2612LoadContext(unsigned char *state, char *version)
|
||||
/* restore YM2612 context */
|
||||
YM2612Restore(state);
|
||||
|
||||
/* extended state */
|
||||
if (version[15] > 0x31)
|
||||
/* extended state (from 1.5.0 and above) */
|
||||
if ((version[11] > 0x31) || (version[13] > 0x34))
|
||||
{
|
||||
int c,s;
|
||||
uint8 index;
|
||||
|
@ -1,12 +1,15 @@
|
||||
/*
|
||||
**
|
||||
** File: ym2612.h -- header for ym2612.c
|
||||
** software implementation of Yamaha FM sound generator
|
||||
** software implementation of Yamaha FM sound generator (YM2612/YM3438)
|
||||
**
|
||||
** Original code (MAME fm.c)
|
||||
**
|
||||
** Copyright (C) 2001, 2002, 2003 Jarek Burczynski (bujar at mame dot net)
|
||||
** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development
|
||||
**
|
||||
** Version 1.4 (final beta)
|
||||
** Version 1.4 (final beta)
|
||||
**
|
||||
** Additional code & fixes by Eke-Eke for Genesis Plus GX
|
||||
**
|
||||
*/
|
||||
|
||||
@ -18,7 +21,6 @@
|
||||
#define INLINE static __inline__
|
||||
#endif
|
||||
|
||||
|
||||
extern int YM2612Init(double clock, int rate);
|
||||
extern int YM2612ResetChip(void);
|
||||
extern void YM2612Update(long int *buffer, int length);
|
||||
@ -30,5 +32,4 @@ extern void YM2612Restore(unsigned char *buffer);
|
||||
extern int YM2612LoadContext(unsigned char *state, char *version);
|
||||
extern int YM2612SaveContext(unsigned char *state);
|
||||
|
||||
|
||||
#endif /* _YM2612_ */
|
||||
|
192
source/state.c
@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* Savestate support
|
||||
*
|
||||
* Copyright (C) 2007, 2008, 2009 Eke-Eke (GCN/Wii port)
|
||||
* Copyright (C) 2007-2011 Eke-Eke (GCN/Wii port)
|
||||
*
|
||||
* 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
|
||||
@ -37,11 +37,18 @@ int state_load(unsigned char *buffer)
|
||||
outbytes = STATE_SIZE;
|
||||
uncompress ((Bytef *)state, &outbytes, (Bytef *)(buffer + 4), inbytes);
|
||||
|
||||
/* version check */
|
||||
/* signature check (GENPLUS-GX x.x.x) */
|
||||
char version[17];
|
||||
load_param(version,16);
|
||||
version[16] = 0;
|
||||
if (strncmp(version,STATE_VERSION,15))
|
||||
if (strncmp(version,STATE_VERSION,11))
|
||||
{
|
||||
free(state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* version check (1.4.0 and above) */
|
||||
if ((version[11] < 0x31) || ((version[11] == 0x31) && (version[13] < 0x34)))
|
||||
{
|
||||
free(state);
|
||||
return -1;
|
||||
@ -51,26 +58,34 @@ int state_load(unsigned char *buffer)
|
||||
system_reset();
|
||||
|
||||
// GENESIS
|
||||
load_param(work_ram, sizeof(work_ram));
|
||||
load_param(zram, sizeof(zram));
|
||||
load_param(&zstate, sizeof(zstate));
|
||||
load_param(&zbank, sizeof(zbank));
|
||||
if (zstate == 3)
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
m68k_memory_map[0xa0].read8 = z80_read_byte;
|
||||
m68k_memory_map[0xa0].read16 = z80_read_word;
|
||||
m68k_memory_map[0xa0].write8 = z80_write_byte;
|
||||
m68k_memory_map[0xa0].write16 = z80_write_word;
|
||||
load_param(work_ram, 0x2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
|
||||
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
|
||||
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
|
||||
load_param(work_ram, sizeof(work_ram));
|
||||
load_param(zram, sizeof(zram));
|
||||
load_param(&zstate, sizeof(zstate));
|
||||
load_param(&zbank, sizeof(zbank));
|
||||
if (zstate == 3)
|
||||
{
|
||||
m68k_memory_map[0xa0].read8 = z80_read_byte;
|
||||
m68k_memory_map[0xa0].read16 = z80_read_word;
|
||||
m68k_memory_map[0xa0].write8 = z80_write_byte;
|
||||
m68k_memory_map[0xa0].write16 = z80_write_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
|
||||
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
|
||||
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
|
||||
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
|
||||
}
|
||||
}
|
||||
|
||||
if (version[15] > 0x30)
|
||||
/* 1.4.1 and above */
|
||||
if ((version[11] > 0x31) || (version[13] > 0x34) || (version[15] > 0x30))
|
||||
{
|
||||
/* extended state */
|
||||
load_param(&mcycles_68k, sizeof(mcycles_68k));
|
||||
@ -78,8 +93,15 @@ int state_load(unsigned char *buffer)
|
||||
}
|
||||
|
||||
// IO
|
||||
load_param(io_reg, sizeof(io_reg));
|
||||
io_reg[0] = region_code | 0x20 | (config.tmss & 1);
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
load_param(&io_reg[0], 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
load_param(io_reg, sizeof(io_reg));
|
||||
io_reg[0] = region_code | 0x20 | (config.tmss & 1);
|
||||
}
|
||||
|
||||
// VDP
|
||||
bufferptr += vdp_context_load(&state[bufferptr], version);
|
||||
@ -88,34 +110,44 @@ int state_load(unsigned char *buffer)
|
||||
bufferptr += sound_context_load(&state[bufferptr], version);
|
||||
|
||||
// 68000
|
||||
uint16 tmp16;
|
||||
uint32 tmp32;
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D0, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D1, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D2, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D3, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D4, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D5, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D6, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D7, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A0, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A1, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A2, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A3, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A4, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A5, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A6, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A7, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_PC, tmp32);
|
||||
load_param(&tmp16, 2); m68k_set_reg(M68K_REG_SR, tmp16);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_USP,tmp32);
|
||||
if (system_hw != SYSTEM_PBC)
|
||||
{
|
||||
uint16 tmp16;
|
||||
uint32 tmp32;
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D0, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D1, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D2, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D3, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D4, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D5, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D6, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D7, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A0, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A1, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A2, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A3, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A4, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A5, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A6, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A7, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_PC, tmp32);
|
||||
load_param(&tmp16, 2); m68k_set_reg(M68K_REG_SR, tmp16);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_USP,tmp32);
|
||||
}
|
||||
|
||||
// Z80
|
||||
load_param(&Z80, sizeof(Z80_Regs));
|
||||
Z80.irq_callback = z80_irq_callback;
|
||||
|
||||
// Cartridge HW
|
||||
bufferptr += cart_hw_context_load(&state[bufferptr], version);
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
bufferptr += sms_cart_context_load(&state[bufferptr], version);
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferptr += md_cart_context_load(&state[bufferptr], version);
|
||||
}
|
||||
|
||||
free(state);
|
||||
return 1;
|
||||
@ -136,15 +168,29 @@ int state_save(unsigned char *buffer)
|
||||
save_param(version, 16);
|
||||
|
||||
// GENESIS
|
||||
save_param(work_ram, sizeof(work_ram));
|
||||
save_param(zram, sizeof(zram));
|
||||
save_param(&zstate, sizeof(zstate));
|
||||
save_param(&zbank, sizeof(zbank));
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
save_param(work_ram, 0x2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
save_param(work_ram, sizeof(work_ram));
|
||||
save_param(zram, sizeof(zram));
|
||||
save_param(&zstate, sizeof(zstate));
|
||||
save_param(&zbank, sizeof(zbank));
|
||||
}
|
||||
save_param(&mcycles_68k, sizeof(mcycles_68k));
|
||||
save_param(&mcycles_z80, sizeof(mcycles_z80));
|
||||
|
||||
// IO
|
||||
save_param(io_reg, sizeof(io_reg));
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
save_param(&io_reg[0], 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
save_param(io_reg, sizeof(io_reg));
|
||||
}
|
||||
|
||||
// VDP
|
||||
bufferptr += vdp_context_save(&state[bufferptr]);
|
||||
@ -153,33 +199,43 @@ int state_save(unsigned char *buffer)
|
||||
bufferptr += sound_context_save(&state[bufferptr]);
|
||||
|
||||
// 68000
|
||||
uint16 tmp16;
|
||||
uint32 tmp32;
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D0); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D1); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D2); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D3); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D4); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D5); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D6); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D7); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A0); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A1); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A2); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A3); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A4); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A5); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A6); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A7); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_PC); save_param(&tmp32, 4);
|
||||
tmp16 = m68k_get_reg(NULL, M68K_REG_SR); save_param(&tmp16, 2);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_USP); save_param(&tmp32, 4);
|
||||
if (system_hw != SYSTEM_PBC)
|
||||
{
|
||||
uint16 tmp16;
|
||||
uint32 tmp32;
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D0); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D1); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D2); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D3); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D4); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D5); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D6); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D7); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A0); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A1); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A2); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A3); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A4); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A5); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A6); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A7); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_PC); save_param(&tmp32, 4);
|
||||
tmp16 = m68k_get_reg(NULL, M68K_REG_SR); save_param(&tmp16, 2);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_USP); save_param(&tmp32, 4);
|
||||
}
|
||||
|
||||
// Z80
|
||||
save_param(&Z80, sizeof(Z80_Regs));
|
||||
|
||||
// Cartridge HW
|
||||
bufferptr += cart_hw_context_save(&state[bufferptr]);
|
||||
if (system_hw == SYSTEM_PBC)
|
||||
{
|
||||
bufferptr += sms_cart_context_save(&state[bufferptr]);
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferptr += md_cart_context_save(&state[bufferptr]);
|
||||
}
|
||||
|
||||
/* compress state file */
|
||||
unsigned long inbytes = bufferptr;
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* Savestate support
|
||||
*
|
||||
* Copyright (C) 2007, 2008, 2009 Eke-Eke (GCN/Wii port)
|
||||
* Copyright (C) 2007-2011 Eke-Eke (GCN/Wii port)
|
||||
*
|
||||
* 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
|
||||
@ -24,7 +24,7 @@
|
||||
#define _STATE_H_
|
||||
|
||||
#define STATE_SIZE 0x48100
|
||||
#define STATE_VERSION "GENPLUS-GX 1.4.2"
|
||||
#define STATE_VERSION "GENPLUS-GX 1.5.0"
|
||||
|
||||
#define load_param(param, size) \
|
||||
memcpy(param, &state[bufferptr], size); \
|
||||
|
666
source/system.c
@ -1,9 +1,9 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Main Emulation
|
||||
* Virtual System emulation
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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
|
||||
@ -32,11 +32,82 @@ uint32 mcycles_vdp;
|
||||
uint32 mcycles_z80;
|
||||
uint32 mcycles_68k;
|
||||
uint8 system_hw;
|
||||
void (*system_frame)(int do_skip);
|
||||
|
||||
static void system_frame_md(int do_skip);
|
||||
static void system_frame_sms(int do_skip);
|
||||
static int pause_b;
|
||||
static EQSTATE eq;
|
||||
static int32 llp,rrp;
|
||||
|
||||
/****************************************************************
|
||||
* AUDIO equalizer
|
||||
* Audio subsystem
|
||||
****************************************************************/
|
||||
static EQSTATE eq;
|
||||
|
||||
int audio_init (int samplerate, float framerate)
|
||||
{
|
||||
/* Shutdown first */
|
||||
audio_shutdown();
|
||||
|
||||
/* Clear the sound data context */
|
||||
memset(&snd, 0, sizeof (snd));
|
||||
|
||||
/* Default settings */
|
||||
snd.sample_rate = samplerate;
|
||||
snd.frame_rate = framerate;
|
||||
|
||||
/* Calculate the sound buffer size (for one frame) */
|
||||
snd.buffer_size = (int)(samplerate / framerate) + 32;
|
||||
|
||||
/* SN76489 stream buffers */
|
||||
snd.psg.buffer = (int16 *) malloc(snd.buffer_size * sizeof(int16));
|
||||
if (!snd.psg.buffer) return (-1);
|
||||
|
||||
/* YM2612 stream buffers */
|
||||
snd.fm.buffer = (int32 *) malloc(snd.buffer_size * sizeof(int32) * 2);
|
||||
if (!snd.fm.buffer) return (-1);
|
||||
|
||||
#ifndef NGC
|
||||
/* Output buffers */
|
||||
snd.buffer[0] = (int16 *) malloc(snd.buffer_size * sizeof(int16));
|
||||
snd.buffer[1] = (int16 *) malloc(snd.buffer_size * sizeof(int16));
|
||||
if (!snd.buffer[0] || !snd.buffer[1]) return (-1);
|
||||
#endif
|
||||
|
||||
/* Resampling buffer */
|
||||
if (config.hq_fm && !Fir_Resampler_initialize(4096)) return (-1);
|
||||
|
||||
/* Set audio enable flag */
|
||||
snd.enabled = 1;
|
||||
|
||||
/* Reset audio */
|
||||
audio_reset();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void audio_reset(void)
|
||||
{
|
||||
/* Low-Pass filter */
|
||||
llp = 0;
|
||||
rrp = 0;
|
||||
|
||||
/* 3 band EQ */
|
||||
audio_set_equalizer();
|
||||
|
||||
/* Resampling buffer */
|
||||
Fir_Resampler_clear();
|
||||
|
||||
/* Audio buffers */
|
||||
snd.psg.pos = snd.psg.buffer;
|
||||
snd.fm.pos = snd.fm.buffer;
|
||||
if (snd.psg.buffer) memset (snd.psg.buffer, 0, snd.buffer_size * sizeof(int16));
|
||||
if (snd.fm.buffer) memset (snd.fm.buffer, 0, snd.buffer_size * sizeof(int32) * 2);
|
||||
#ifndef NGC
|
||||
if (snd.buffer[0]) memset (snd.buffer[0], 0, snd.buffer_size * sizeof(int16));
|
||||
if (snd.buffer[1]) memset (snd.buffer[1], 0, snd.buffer_size * sizeof(int16));
|
||||
#endif
|
||||
}
|
||||
|
||||
void audio_set_equalizer(void)
|
||||
{
|
||||
@ -46,10 +117,19 @@ void audio_set_equalizer(void)
|
||||
eq.hg = (double)(config.hg) / 100.0;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* AUDIO stream update & mixing
|
||||
****************************************************************/
|
||||
static int32 llp,rrp;
|
||||
void audio_shutdown(void)
|
||||
{
|
||||
/* Sound buffers */
|
||||
if (snd.fm.buffer) free(snd.fm.buffer);
|
||||
if (snd.psg.buffer) free(snd.psg.buffer);
|
||||
#ifndef NGC
|
||||
if (snd.buffer[0]) free(snd.buffer[0]);
|
||||
if (snd.buffer[1]) free(snd.buffer[1]);
|
||||
#endif
|
||||
|
||||
/* Resampling buffer */
|
||||
Fir_Resampler_shutdown();
|
||||
}
|
||||
|
||||
int audio_update (void)
|
||||
{
|
||||
@ -129,14 +209,10 @@ int audio_update (void)
|
||||
}
|
||||
|
||||
/* clipping (16-bit samples) */
|
||||
if (l > 32767)
|
||||
l = 32767;
|
||||
else if (l < -32768)
|
||||
l = -32768;
|
||||
if (r > 32767)
|
||||
r = 32767;
|
||||
else if (r < -32768)
|
||||
r = -32768;
|
||||
if (l > 32767) l = 32767;
|
||||
else if (l < -32768) l = -32768;
|
||||
if (r > 32767) r = 32767;
|
||||
else if (r < -32768) r = -32768;
|
||||
|
||||
/* update sound buffer */
|
||||
#ifndef NGC
|
||||
@ -163,181 +239,58 @@ int audio_update (void)
|
||||
return size;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* AUDIO System initialization
|
||||
****************************************************************/
|
||||
int audio_init (int samplerate, float framerate)
|
||||
{
|
||||
/* Shutdown first */
|
||||
audio_shutdown();
|
||||
|
||||
/* Clear the sound data context */
|
||||
memset(&snd, 0, sizeof (snd));
|
||||
|
||||
/* Default settings */
|
||||
snd.sample_rate = samplerate;
|
||||
snd.frame_rate = framerate;
|
||||
|
||||
/* Calculate the sound buffer size (for one frame) */
|
||||
snd.buffer_size = (int)(samplerate / framerate) + 32;
|
||||
|
||||
#ifndef NGC
|
||||
/* Output buffers */
|
||||
snd.buffer[0] = (int16 *) malloc(snd.buffer_size * sizeof(int16));
|
||||
snd.buffer[1] = (int16 *) malloc(snd.buffer_size * sizeof(int16));
|
||||
if (!snd.buffer[0] || !snd.buffer[1])
|
||||
return (-1);
|
||||
#endif
|
||||
|
||||
/* SN76489 stream buffers */
|
||||
snd.psg.buffer = (int16 *) malloc(snd.buffer_size * sizeof(int16));
|
||||
if (!snd.psg.buffer)
|
||||
return (-1);
|
||||
|
||||
/* YM2612 stream buffers */
|
||||
snd.fm.buffer = (int32 *) malloc(snd.buffer_size * sizeof(int32) * 2);
|
||||
if (!snd.fm.buffer)
|
||||
return (-1);
|
||||
|
||||
/* Resampling buffer */
|
||||
if (config.hq_fm)
|
||||
{
|
||||
if (!Fir_Resampler_initialize(4096))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set audio enable flag */
|
||||
snd.enabled = 1;
|
||||
|
||||
/* Reset audio */
|
||||
audio_reset();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* AUDIO System reset
|
||||
****************************************************************/
|
||||
void audio_reset(void)
|
||||
{
|
||||
/* Low-Pass filter */
|
||||
llp = 0;
|
||||
rrp = 0;
|
||||
|
||||
/* 3 band EQ */
|
||||
audio_set_equalizer();
|
||||
|
||||
/* audio buffers */
|
||||
Fir_Resampler_clear();
|
||||
snd.psg.pos = snd.psg.buffer;
|
||||
snd.fm.pos = snd.fm.buffer;
|
||||
#ifndef NGC
|
||||
if (snd.buffer[0])
|
||||
memset (snd.buffer[0], 0, snd.buffer_size * sizeof(int16));
|
||||
if (snd.buffer[1])
|
||||
memset (snd.buffer[1], 0, snd.buffer_size * sizeof(int16));
|
||||
#endif
|
||||
if (snd.psg.buffer)
|
||||
memset (snd.psg.buffer, 0, snd.buffer_size * sizeof(int16));
|
||||
if (snd.fm.buffer)
|
||||
memset (snd.fm.buffer, 0, snd.buffer_size * sizeof(int32) * 2);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* AUDIO System shutdown
|
||||
****************************************************************/
|
||||
void audio_shutdown(void)
|
||||
{
|
||||
/* Sound buffers */
|
||||
#ifndef NGC
|
||||
if (snd.buffer[0])
|
||||
free(snd.buffer[0]);
|
||||
if (snd.buffer[1])
|
||||
free(snd.buffer[1]);
|
||||
#endif
|
||||
if (snd.fm.buffer)
|
||||
free(snd.fm.buffer);
|
||||
if (snd.psg.buffer)
|
||||
free(snd.psg.buffer);
|
||||
|
||||
/* Resampling buffer */
|
||||
Fir_Resampler_shutdown();
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* Virtual Genesis initialization
|
||||
****************************************************************/
|
||||
void system_init (void)
|
||||
void system_init(void)
|
||||
{
|
||||
/* Genesis hardware */
|
||||
gen_init();
|
||||
io_init();
|
||||
vdp_init();
|
||||
render_init();
|
||||
|
||||
/* Cartridge hardware */
|
||||
cart_hw_init();
|
||||
|
||||
/* Sound hardware */
|
||||
sound_init();
|
||||
system_frame = (system_hw == SYSTEM_PBC) ? system_frame_sms : system_frame_md;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* Virtual Genesis Hard Reset
|
||||
* Virtual System emulation
|
||||
****************************************************************/
|
||||
void system_reset (void)
|
||||
void system_reset(void)
|
||||
{
|
||||
/* Cartridge Hardware */
|
||||
cart_hw_reset(1);
|
||||
|
||||
/* Genesis hardware */
|
||||
gen_hardreset();
|
||||
gen_reset(1);
|
||||
io_reset();
|
||||
vdp_reset();
|
||||
render_reset();
|
||||
|
||||
/* Sound hardware */
|
||||
sound_reset();
|
||||
|
||||
/* Audio system */
|
||||
audio_reset();
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* Virtual Genesis shutdown
|
||||
****************************************************************/
|
||||
void system_shutdown (void)
|
||||
{
|
||||
gen_shutdown ();
|
||||
vdp_shutdown ();
|
||||
render_shutdown ();
|
||||
SN76489_Shutdown ();
|
||||
gen_shutdown();
|
||||
SN76489_Shutdown();
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* Virtual Genesis Frame emulation
|
||||
****************************************************************/
|
||||
|
||||
void system_frame (int do_skip)
|
||||
static void system_frame_md(int do_skip)
|
||||
{
|
||||
/* line counter */
|
||||
int line = 0;
|
||||
|
||||
/* Z80 interrupt flag */
|
||||
int zirq = 0;
|
||||
|
||||
int zirq = 1;
|
||||
|
||||
/* reload H Counter */
|
||||
int h_counter = reg[10];
|
||||
|
||||
/* reset line master cycle count */
|
||||
mcycles_vdp = 0;
|
||||
|
||||
/* reload V Counter */
|
||||
v_counter = lines_per_frame - 1;
|
||||
|
||||
/* reset VDP FIFO */
|
||||
fifo_write_cnt = 0;
|
||||
fifo_lastwrite = 0;
|
||||
|
||||
/* reset line cycle count */
|
||||
mcycles_vdp = 0;
|
||||
fifo_write_cnt = 0;
|
||||
fifo_lastwrite = 0;
|
||||
|
||||
/* update 6-Buttons & Lightguns */
|
||||
input_refresh();
|
||||
@ -349,34 +302,43 @@ void system_frame (int do_skip)
|
||||
|
||||
/* interlaced mode */
|
||||
int old_interlaced = interlaced;
|
||||
interlaced = (reg[12] & 2) >> 1;
|
||||
interlaced = (reg[12] & 0x02) >> 1;
|
||||
if (old_interlaced != interlaced)
|
||||
{
|
||||
im2_flag = ((reg[12] & 6) == 6);
|
||||
im2_flag = ((reg[12] & 0x06) == 0x06);
|
||||
odd_frame = 1;
|
||||
bitmap.viewport.changed = 5;
|
||||
|
||||
/* update rendering mode */
|
||||
if (reg[1] & 0x04)
|
||||
{
|
||||
if (im2_flag)
|
||||
{
|
||||
render_bg = (reg[11] & 0x04) ? render_bg_m5_im2_vs : render_bg_m5_im2;
|
||||
render_obj = (reg[12] & 0x08) ? render_obj_m5_im2_ste : render_obj_m5_im2;
|
||||
}
|
||||
else
|
||||
{
|
||||
render_bg = (reg[11] & 0x04) ? render_bg_m5_vs : render_bg_m5;
|
||||
render_obj = (reg[12] & 0x08) ? render_obj_m5_ste : render_obj_m5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* active screen height */
|
||||
bitmap.viewport.h = 224 + ((reg[1] & 8) << 1);
|
||||
bitmap.viewport.y = (config.overscan & 1) * (8 - (reg[1] & 8) + vdp_pal*24);
|
||||
if (reg[1] & 0x04)
|
||||
{
|
||||
bitmap.viewport.h = 224 + ((reg[1] & 0x08) << 1);
|
||||
bitmap.viewport.y = (config.overscan & 1) * ((240 + 48*vdp_pal - bitmap.viewport.h) >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap.viewport.h = 192;
|
||||
bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1);
|
||||
}
|
||||
|
||||
/* active screen width */
|
||||
bitmap.viewport.w = 256 + ((reg[12] & 1) << 6);
|
||||
bitmap.viewport.x = (config.overscan & 2) * 7;
|
||||
}
|
||||
|
||||
/* render last line of overscan */
|
||||
if (!do_skip && bitmap.viewport.y)
|
||||
{
|
||||
render_line(v_counter);
|
||||
}
|
||||
|
||||
/* parse first line of sprites */
|
||||
object_which = 1;
|
||||
if (reg[1] & 0x40)
|
||||
{
|
||||
parse_satb(0x80);
|
||||
bitmap.viewport.w = 256 + ((reg[12] & 0x01) << 6);
|
||||
}
|
||||
|
||||
/* clear VBLANK, DMA, FIFO FULL & field flags */
|
||||
@ -395,7 +357,19 @@ void system_frame (int do_skip)
|
||||
/* update VDP DMA */
|
||||
if (dma_length)
|
||||
{
|
||||
vdp_update_dma(0);
|
||||
vdp_dma_update(0);
|
||||
}
|
||||
|
||||
/* render last line of overscan */
|
||||
if (bitmap.viewport.y)
|
||||
{
|
||||
blank_line(v_counter, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
|
||||
}
|
||||
|
||||
/* parse first line of sprites */
|
||||
if (reg[1] & 0x40)
|
||||
{
|
||||
parse_satb(-1);
|
||||
}
|
||||
|
||||
/* run 68k & Z80 */
|
||||
@ -437,31 +411,22 @@ void system_frame (int do_skip)
|
||||
hint_pending = 0x10;
|
||||
if (reg[0] & 0x10)
|
||||
{
|
||||
irq_status = (irq_status & 2) | 0x14;
|
||||
m68k_irq_state |= 0x14;
|
||||
}
|
||||
}
|
||||
|
||||
/* update VDP DMA */
|
||||
if (dma_length)
|
||||
{
|
||||
vdp_update_dma(mcycles_vdp);
|
||||
vdp_dma_update(mcycles_vdp);
|
||||
}
|
||||
|
||||
/* swap sprite line buffers */
|
||||
object_which ^= 1;
|
||||
|
||||
/* render scanline */
|
||||
if (!do_skip)
|
||||
{
|
||||
render_line(line);
|
||||
}
|
||||
|
||||
/* parse next line of sprites */
|
||||
if ((reg[1] & 0x40) && (line < (bitmap.viewport.h - 1)))
|
||||
{
|
||||
parse_satb(0x81 + line);
|
||||
}
|
||||
|
||||
/* run 68k & Z80 */
|
||||
m68k_run(mcycles_vdp + MCYCLES_PER_LINE);
|
||||
if (zstate == 1)
|
||||
@ -487,22 +452,8 @@ void system_frame (int do_skip)
|
||||
/* end of active display */
|
||||
v_counter = line;
|
||||
|
||||
/* update 6-Buttons & Lightguns */
|
||||
input_refresh();
|
||||
|
||||
/* H Interrupt */
|
||||
if(--h_counter < 0)
|
||||
{
|
||||
/* reload H Counter */
|
||||
h_counter = reg[10];
|
||||
|
||||
/* interrupt level 4 */
|
||||
hint_pending = 0x10;
|
||||
if (reg[0] & 0x10)
|
||||
{
|
||||
irq_status = (irq_status & 2) | 0x14;
|
||||
}
|
||||
}
|
||||
/* set VBLANK flag */
|
||||
status |= 0x08;
|
||||
|
||||
/* overscan area */
|
||||
int start = lines_per_frame - bitmap.viewport.y;
|
||||
@ -516,19 +467,33 @@ void system_frame (int do_skip)
|
||||
bitmap.viewport.changed |= 1;
|
||||
}
|
||||
|
||||
/* set VBLANK flag */
|
||||
status |= 0x08;
|
||||
/* update 6-Buttons & Lightguns */
|
||||
input_refresh();
|
||||
|
||||
/* H Interrupt */
|
||||
if(--h_counter < 0)
|
||||
{
|
||||
/* reload H Counter */
|
||||
h_counter = reg[10];
|
||||
|
||||
/* interrupt level 4 */
|
||||
hint_pending = 0x10;
|
||||
if (reg[0] & 0x10)
|
||||
{
|
||||
m68k_irq_state |= 0x14;
|
||||
}
|
||||
}
|
||||
|
||||
/* update VDP DMA */
|
||||
if (dma_length)
|
||||
{
|
||||
vdp_update_dma(mcycles_vdp);
|
||||
vdp_dma_update(mcycles_vdp);
|
||||
}
|
||||
|
||||
/* render overscan */
|
||||
if (!do_skip && (line < end))
|
||||
if (line < end)
|
||||
{
|
||||
render_line(line);
|
||||
blank_line(line, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
|
||||
}
|
||||
|
||||
/* update inputs before VINT (Warriors of Eternal Sun) */
|
||||
@ -553,14 +518,13 @@ void system_frame (int do_skip)
|
||||
vint_pending = 0x20;
|
||||
if (reg[1] & 0x20)
|
||||
{
|
||||
irq_status = 0x16;
|
||||
m68k_irq_state = 0x16;
|
||||
}
|
||||
|
||||
/* Z80 interrupt */
|
||||
z80_set_irq_line(0, ASSERT_LINE);
|
||||
zirq = 1;
|
||||
/* assert Z80 interrupt */
|
||||
Z80.irq_state = ASSERT_LINE;
|
||||
|
||||
/* run 68k & Z80 */
|
||||
/* run 68k & Z80 until end of line */
|
||||
m68k_run(mcycles_vdp + MCYCLES_PER_LINE);
|
||||
if (zstate == 1)
|
||||
{
|
||||
@ -593,14 +557,14 @@ void system_frame (int do_skip)
|
||||
input_refresh();
|
||||
|
||||
/* render overscan */
|
||||
if (!do_skip && ((line < end) || (line >= start)))
|
||||
if ((line < end) || (line >= start))
|
||||
{
|
||||
render_line(line);
|
||||
blank_line(line, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
|
||||
}
|
||||
|
||||
/* Z80 interrupt is asserted for one line */
|
||||
if (zirq)
|
||||
{
|
||||
/* Z80 interrupt is asserted exactly for one line */
|
||||
m68k_run(mcycles_vdp + 788);
|
||||
if (zstate == 1)
|
||||
{
|
||||
@ -612,7 +576,7 @@ void system_frame (int do_skip)
|
||||
}
|
||||
|
||||
/* clear Z80 interrupt */
|
||||
z80_set_irq_line(0, CLEAR_LINE);
|
||||
Z80.irq_state = CLEAR_LINE;
|
||||
zirq = 0;
|
||||
}
|
||||
|
||||
@ -638,7 +602,277 @@ void system_frame (int do_skip)
|
||||
}
|
||||
while (++line < (lines_per_frame - 1));
|
||||
|
||||
/* adjust cpu cycle count for next frame */
|
||||
/* adjust 68k & Z80 cycle count for next frame */
|
||||
mcycles_68k -= mcycles_vdp;
|
||||
mcycles_z80 -= mcycles_vdp;
|
||||
}
|
||||
|
||||
|
||||
static void system_frame_sms(int do_skip)
|
||||
{
|
||||
/* line counter */
|
||||
int line = 0;
|
||||
|
||||
/* reload H Counter */
|
||||
int h_counter = reg[10];
|
||||
|
||||
/* reset line master cycle count */
|
||||
mcycles_vdp = 0;
|
||||
|
||||
/* reload V Counter */
|
||||
v_counter = lines_per_frame - 1;
|
||||
|
||||
/* reset VDP FIFO */
|
||||
fifo_write_cnt = 0;
|
||||
fifo_lastwrite = 0;
|
||||
|
||||
/* update 6-Buttons & Lightguns */
|
||||
input_refresh();
|
||||
|
||||
/* display changed during VBLANK */
|
||||
if (bitmap.viewport.changed & 2)
|
||||
{
|
||||
bitmap.viewport.changed &= ~2;
|
||||
|
||||
/* interlaced mode */
|
||||
int old_interlaced = interlaced;
|
||||
interlaced = (reg[12] & 0x02) >> 1;
|
||||
if (old_interlaced != interlaced)
|
||||
{
|
||||
im2_flag = ((reg[12] & 0x06) == 0x06);
|
||||
odd_frame = 1;
|
||||
bitmap.viewport.changed = 5;
|
||||
|
||||
/* update rendering mode */
|
||||
if (reg[1] & 0x04)
|
||||
{
|
||||
if (im2_flag)
|
||||
{
|
||||
render_bg = (reg[11] & 0x04) ? render_bg_m5_im2_vs : render_bg_m5_im2;
|
||||
render_obj = render_obj_m5_im2;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
render_bg = (reg[11] & 0x04) ? render_bg_m5_vs : render_bg_m5;
|
||||
render_obj = render_obj_m5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* active screen height */
|
||||
if (reg[1] & 0x04)
|
||||
{
|
||||
bitmap.viewport.h = 224 + ((reg[1] & 0x08) << 1);
|
||||
bitmap.viewport.y = (config.overscan & 1) * ((240 + 48*vdp_pal - bitmap.viewport.h) >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap.viewport.h = 192;
|
||||
bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1);
|
||||
}
|
||||
|
||||
/* active screen width */
|
||||
bitmap.viewport.w = 256 + ((reg[12] & 0x01) << 6);
|
||||
}
|
||||
|
||||
/* Detect pause button input */
|
||||
if (input.pad[0] & INPUT_START)
|
||||
{
|
||||
/* NMI is edge-triggered */
|
||||
if (!pause_b)
|
||||
{
|
||||
pause_b = 1;
|
||||
z80_set_nmi_line(ASSERT_LINE);
|
||||
z80_set_nmi_line(CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pause_b = 0;
|
||||
}
|
||||
|
||||
/* 3-D glasses faking: skip rendering of left lens frame */
|
||||
do_skip |= (work_ram[0x1ffb] & cart.special);
|
||||
|
||||
/* clear VBLANK, DMA, FIFO FULL & field flags */
|
||||
status &= 0xFEE5;
|
||||
|
||||
/* set FIFO EMPTY flag */
|
||||
status |= 0x0200;
|
||||
|
||||
/* even/odd field flag (interlaced modes only) */
|
||||
odd_frame ^= 1;
|
||||
if (interlaced)
|
||||
{
|
||||
status |= (odd_frame << 4);
|
||||
}
|
||||
|
||||
/* update VDP DMA */
|
||||
if (dma_length)
|
||||
{
|
||||
vdp_dma_update(0);
|
||||
}
|
||||
|
||||
/* render last line of overscan */
|
||||
if (bitmap.viewport.y)
|
||||
{
|
||||
blank_line(v_counter, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
|
||||
}
|
||||
|
||||
/* parse first line of sprites */
|
||||
if (reg[1] & 0x40)
|
||||
{
|
||||
parse_satb(-1);
|
||||
}
|
||||
|
||||
/* latch Horizontal Scroll register (if modified during VBLANK) */
|
||||
hscroll = reg[0x08];
|
||||
|
||||
/* run Z80 */
|
||||
z80_run(MCYCLES_PER_LINE);
|
||||
|
||||
/* update line cycle count */
|
||||
mcycles_vdp += MCYCLES_PER_LINE;
|
||||
|
||||
/* latch Vertical Scroll register */
|
||||
vscroll = reg[0x09];
|
||||
|
||||
/* Active Display */
|
||||
do
|
||||
{
|
||||
/* update V Counter */
|
||||
v_counter = line;
|
||||
|
||||
/* update 6-Buttons & Lightguns */
|
||||
input_refresh();
|
||||
|
||||
/* H Interrupt */
|
||||
if(--h_counter < 0)
|
||||
{
|
||||
/* reload H Counter */
|
||||
h_counter = reg[10];
|
||||
|
||||
/* interrupt level 4 */
|
||||
hint_pending = 0x10;
|
||||
if (reg[0] & 0x10)
|
||||
{
|
||||
Z80.irq_state = ASSERT_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
/* update VDP DMA */
|
||||
if (dma_length)
|
||||
{
|
||||
vdp_dma_update(mcycles_vdp);
|
||||
}
|
||||
|
||||
/* render scanline */
|
||||
if (!do_skip)
|
||||
{
|
||||
render_line(line);
|
||||
}
|
||||
|
||||
/* run Z80 */
|
||||
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
|
||||
|
||||
/* update line cycle count */
|
||||
mcycles_vdp += MCYCLES_PER_LINE;
|
||||
}
|
||||
while (++line < bitmap.viewport.h);
|
||||
|
||||
/* end of active display */
|
||||
v_counter = line;
|
||||
|
||||
/* set VBLANK flag */
|
||||
status |= 0x08;
|
||||
|
||||
/* overscan area */
|
||||
int start = lines_per_frame - bitmap.viewport.y;
|
||||
int end = bitmap.viewport.h + bitmap.viewport.y;
|
||||
|
||||
/* check viewport changes */
|
||||
if ((bitmap.viewport.w != bitmap.viewport.ow) || (bitmap.viewport.h != bitmap.viewport.oh))
|
||||
{
|
||||
bitmap.viewport.ow = bitmap.viewport.w;
|
||||
bitmap.viewport.oh = bitmap.viewport.h;
|
||||
bitmap.viewport.changed |= 1;
|
||||
}
|
||||
|
||||
/* update 6-Buttons & Lightguns */
|
||||
input_refresh();
|
||||
|
||||
/* H Interrupt */
|
||||
if(--h_counter < 0)
|
||||
{
|
||||
/* reload H Counter */
|
||||
h_counter = reg[10];
|
||||
|
||||
/* interrupt level 4 */
|
||||
hint_pending = 0x10;
|
||||
if (reg[0] & 0x10)
|
||||
{
|
||||
Z80.irq_state = ASSERT_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
/* update VDP DMA */
|
||||
if (dma_length)
|
||||
{
|
||||
vdp_dma_update(mcycles_vdp);
|
||||
}
|
||||
|
||||
/* render overscan */
|
||||
if (line < end)
|
||||
{
|
||||
blank_line(line, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
|
||||
}
|
||||
|
||||
/* update inputs before VINT (Warriors of Eternal Sun) */
|
||||
osd_input_Update();
|
||||
|
||||
/* run Z80 until end of line */
|
||||
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
|
||||
|
||||
/* VINT flag */
|
||||
status |= 0x80;
|
||||
|
||||
/* V Interrupt */
|
||||
vint_pending = 0x20;
|
||||
if (reg[1] & 0x20)
|
||||
{
|
||||
Z80.irq_state = ASSERT_LINE;
|
||||
}
|
||||
|
||||
/* update line cycle count */
|
||||
mcycles_vdp += MCYCLES_PER_LINE;
|
||||
|
||||
/* increment line count */
|
||||
line++;
|
||||
|
||||
/* Vertical Blanking */
|
||||
do
|
||||
{
|
||||
/* update V Counter */
|
||||
v_counter = line;
|
||||
|
||||
/* update 6-Buttons & Lightguns */
|
||||
input_refresh();
|
||||
|
||||
/* render overscan */
|
||||
if ((line < end) || (line >= start))
|
||||
{
|
||||
blank_line(line, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
|
||||
}
|
||||
|
||||
/* run Z80 */
|
||||
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
|
||||
|
||||
/* update line cycle count */
|
||||
mcycles_vdp += MCYCLES_PER_LINE;
|
||||
}
|
||||
while (++line < (lines_per_frame - 1));
|
||||
|
||||
/* adjust Z80 cycle count for next frame */
|
||||
mcycles_z80 -= mcycles_vdp;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Main Emulation
|
||||
* Virtual System Emulation
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* 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
|
||||
@ -24,18 +24,21 @@
|
||||
#ifndef _SYSTEM_H_
|
||||
#define _SYSTEM_H_
|
||||
|
||||
#define SYSTEM_GENESIS 0
|
||||
#define SYSTEM_MEGADRIVE 1
|
||||
#define SYSTEM_PICO 2
|
||||
#define SYSTEM_PBC 0x00
|
||||
#define SYSTEM_GENESIS 0x01
|
||||
#define SYSTEM_MEGADRIVE 0x02
|
||||
#define SYSTEM_PICO 0x03
|
||||
|
||||
#define MCYCLES_PER_LINE 3420
|
||||
|
||||
#define Z80_CYCLE_OFFSET 550 /* horizontal timings offset when running in SMS mode */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8 *data; /* Bitmap data */
|
||||
int width; /* Bitmap width (32+512+32) */
|
||||
int height; /* Bitmap height (256) */
|
||||
int depth; /* Color depth (8 bits) */
|
||||
int width; /* Bitmap width */
|
||||
int height; /* Bitmap height */
|
||||
int depth; /* Color depth (8-32 bits) */
|
||||
int pitch; /* Width of bitmap in bytes */
|
||||
int granularity; /* Size of each pixel in bytes */
|
||||
int remap; /* 1= Translate pixel data */
|
||||
@ -51,7 +54,6 @@ typedef struct
|
||||
} viewport;
|
||||
} t_bitmap;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int sample_rate; /* Output Sample rate (8000-48000) */
|
||||
@ -71,12 +73,13 @@ typedef struct
|
||||
} psg;
|
||||
} t_snd;
|
||||
|
||||
|
||||
/* Global variables */
|
||||
extern t_bitmap bitmap;
|
||||
extern t_snd snd;
|
||||
extern uint32 mcycles_vdp;
|
||||
extern uint32 mcycles_z80;
|
||||
extern uint32 mcycles_68k;
|
||||
extern uint32 mcycles_vdp;
|
||||
extern uint8 system_hw;
|
||||
|
||||
/* Function prototypes */
|
||||
@ -88,7 +91,7 @@ extern void audio_set_equalizer(void);
|
||||
extern void system_init(void);
|
||||
extern void system_reset(void);
|
||||
extern void system_shutdown(void);
|
||||
extern void system_frame(int do_skip);
|
||||
extern void (*system_frame)(int do_skip);
|
||||
|
||||
#endif /* _SYSTEM_H_ */
|
||||
|
||||
|
@ -19,52 +19,63 @@ FLAGS = -I. -I.. -I../z80 -I../m68k -I../dos -I../sound -I../sound/SRC -I../cart
|
||||
|
||||
LIBS = -lalleg -laudio -lz -lm
|
||||
|
||||
OBJ = obj/z80.o
|
||||
OBJECTS = obj/z80.o
|
||||
|
||||
OBJ += obj/m68kcpu.o \
|
||||
OBJECTS += obj/m68kcpu.o \
|
||||
obj/m68kops.o
|
||||
|
||||
OBJ += obj/genesis.o \
|
||||
obj/vdp.o \
|
||||
obj/render.o \
|
||||
obj/system.o \
|
||||
obj/gen_io.o \
|
||||
obj/gen_input.o \
|
||||
obj/mem68k.o \
|
||||
obj/memz80.o \
|
||||
obj/membnk.o \
|
||||
|
||||
OBJECTS += obj/genesis.o \
|
||||
obj/vdp_ctrl.o \
|
||||
obj/vdp_render.o \
|
||||
obj/system.o \
|
||||
obj/io_ctrl.o \
|
||||
obj/mem68k.o \
|
||||
obj/memz80.o \
|
||||
obj/membnk.o \
|
||||
obj/state.o
|
||||
|
||||
OBJ += obj/sound.o \
|
||||
obj/sn76489.o \
|
||||
OBJECTS += obj/input.o \
|
||||
obj/gamepad.o \
|
||||
obj/lightgun.o \
|
||||
obj/mouse.o \
|
||||
obj/activator.o \
|
||||
obj/xe_a1p.o \
|
||||
obj/teamplayer.o \
|
||||
obj/paddle.o \
|
||||
obj/sportspad.o
|
||||
|
||||
|
||||
OBJECTS += obj/sound.o \
|
||||
obj/sn76489.o \
|
||||
obj/ym2612.o
|
||||
|
||||
OBJ += obj/samplerate.o \
|
||||
obj/src_linear.o \
|
||||
obj/src_sinc.o \
|
||||
obj/src_zoh.o \
|
||||
OBJECTS += obj/Fir_Resampler.o
|
||||
OBJECTS += obj/blip.o
|
||||
|
||||
OBJ += obj/blip.o \
|
||||
OBJECTS += obj/eq.o \
|
||||
|
||||
OBJ += obj/eq.o \
|
||||
|
||||
OBJ += obj/sram.o \
|
||||
OBJECTS += obj/sram.o \
|
||||
obj/eeprom.o \
|
||||
obj/svp.o \
|
||||
obj/ssp16.o \
|
||||
obj/cart_hw.o
|
||||
obj/ggenie.o \
|
||||
obj/areplay.o \
|
||||
obj/md_cart.o \
|
||||
obj/sms_cart.o
|
||||
|
||||
OBJ += obj/dos.o \
|
||||
obj/sealintf.o \
|
||||
OBJECTS += obj/dos.o \
|
||||
obj/sealintf.o \
|
||||
obj/config.o \
|
||||
obj/error.o \
|
||||
obj/unzip.o \
|
||||
obj/fileio.o \
|
||||
obj/loadrom.o
|
||||
|
||||
OBJ += obj/sms_ntsc.o \
|
||||
OBJECTS += obj/sms_ntsc.o \
|
||||
obj/md_ntsc.o
|
||||
|
||||
|
||||
EXE = ../gen.exe
|
||||
|
||||
all : $(EXE)
|
||||
@ -88,6 +99,9 @@ obj/%.o : ../sound/SRC/%.c ../sound/SRC/%.h
|
||||
obj/%.o : ../sound/SRC/%.c
|
||||
$(CC) -c $< -o $@ $(FLAGS)
|
||||
|
||||
obj/%.o : ../input_hw/%.c ../input_hw/%.h
|
||||
$(CC) -c $< -o $@ $(FLAGS)
|
||||
|
||||
obj/%.o : ../cart_hw/%.c ../cart_hw/%.h
|
||||
$(CC) -c $< -o $@ $(FLAGS)
|
||||
|
||||
|
@ -122,13 +122,13 @@ void set_config_defaults(void)
|
||||
config.render = 0;
|
||||
|
||||
/* controllers options */
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_GAMEPAD;
|
||||
input.system[0] = SYSTEM_MD_GAMEPAD;
|
||||
input.system[1] = SYSTEM_MD_GAMEPAD;
|
||||
config.gun_cursor[0] = 1;
|
||||
config.gun_cursor[1] = 1;
|
||||
config.invert_mouse = 0;
|
||||
for (i=0;i<MAX_INPUTS;i++)
|
||||
config.input[i].padtype = DEVICE_3BUTTON;
|
||||
config.input[i].padtype = DEVICE_PAD3B;
|
||||
}
|
||||
|
||||
|
||||
|
@ -286,8 +286,8 @@ void dos_update_input(void)
|
||||
poll_mouse();
|
||||
|
||||
/* Calculate X Y axis values */
|
||||
input.analog[joynum - 4][0] = (mouse_x * bitmap.viewport.w) / SCREEN_W;
|
||||
input.analog[joynum - 4][1] = (mouse_y * bitmap.viewport.h) / SCREEN_H;
|
||||
input.analog[joynum][0] = (mouse_x * bitmap.viewport.w) / SCREEN_W;
|
||||
input.analog[joynum][1] = (mouse_y * bitmap.viewport.h) / SCREEN_H;
|
||||
|
||||
/* Map mouse buttons to player #1 inputs */
|
||||
if(mouse_b & 4) input.pad[joynum] |= INPUT_C;
|
||||
@ -301,14 +301,14 @@ void dos_update_input(void)
|
||||
poll_mouse();
|
||||
|
||||
/* Get X & Y quantity of movement */
|
||||
get_mouse_mickeys(&input.analog[2][0], &input.analog[2][1]);
|
||||
get_mouse_mickeys(&input.analog[joynum][0], &input.analog[joynum][1]);
|
||||
|
||||
/* Sega Mouse range is -256;+256 */
|
||||
input.analog[2][0] = (input.analog[2][0] * 256) / SCREEN_W;
|
||||
input.analog[2][1] = (input.analog[2][1] * 256) / SCREEN_H;
|
||||
input.analog[joynum][0] = (input.analog[joynum][0] * 256) / SCREEN_W;
|
||||
input.analog[joynum][1] = (input.analog[joynum][1] * 256) / SCREEN_H;
|
||||
|
||||
/* Vertical movement is upsidedown */
|
||||
if (!config.invert_mouse) input.analog[2][1] = 0 - input.analog[2][1];
|
||||
if (!config.invert_mouse) input.analog[joynum][1] = 0 - input.analog[joynum][1];
|
||||
|
||||
/* Map mouse buttons to player #1 inputs */
|
||||
if(mouse_b & 4) input.pad[joynum] |= INPUT_C;
|
||||
@ -383,11 +383,15 @@ void dos_update_input(void)
|
||||
}
|
||||
|
||||
/* reinitialize VC max value */
|
||||
vc_max = 0xEA + 24*vdp_pal;
|
||||
if (reg[1] & 8)
|
||||
static const uint16 vc_table[4][2] =
|
||||
{
|
||||
vc_max += (28 - 20*vdp_pal);
|
||||
}
|
||||
/* NTSC, PAL */
|
||||
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||
{0xEA , 0x102}, /* Mode 5 (224 lines) */
|
||||
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||
{0x106, 0x10A} /* Mode 5 (240 lines) */
|
||||
};
|
||||
vc_max = vc_table[(reg[1] >> 2) & 3][vdp_pal];
|
||||
|
||||
/* reinitialize overscan area */
|
||||
bitmap.viewport.y = (config.overscan & 1) ? (((reg[1] & 8) ? 0 : 8) + (vdp_pal ? 24 : 0)) : 0;
|
||||
|
@ -27,7 +27,7 @@ uint8 *load_archive(char *filename, int *file_size)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ret = unzGetCurrentFileInfo(fd, &info, NULL, 0, NULL, 0, NULL, 0);
|
||||
ret = unzGetCurrentFileInfo(fd, &info, filename, 128, NULL, 0, NULL, 0);
|
||||
if(ret != UNZ_OK)
|
||||
{
|
||||
unzClose(fd);
|
||||
|
@ -19,7 +19,7 @@ CFLAGS = `sdl-config --cflags` -march=i686 -O6 -fomit-frame-pointer -Wall -Wn
|
||||
#LDFLAGS = -pg
|
||||
DEFINES = -DLSB_FIRST
|
||||
|
||||
INCLUDES = -I. -I.. -I../z80 -I../m68k -I../sound -I../cart_hw -I../cart_hw/svp -I../ntsc
|
||||
INCLUDES = -I. -I.. -I../z80 -I../m68k -I../sound -I../input_hw -I../cart_hw -I../cart_hw/svp -I../ntsc
|
||||
LIBS = `sdl-config --libs` -lz -lm
|
||||
|
||||
OBJECTS = obj/z80.o
|
||||
@ -28,19 +28,29 @@ OBJECTS += obj/m68kcpu.o \
|
||||
obj/m68kops.o
|
||||
|
||||
|
||||
OBJECTS += obj/genesis.o \
|
||||
obj/vdp.o \
|
||||
obj/render.o \
|
||||
obj/system.o \
|
||||
obj/gen_io.o \
|
||||
obj/gen_input.o \
|
||||
obj/mem68k.o \
|
||||
obj/memz80.o \
|
||||
obj/membnk.o \
|
||||
OBJECTS += obj/genesis.o \
|
||||
obj/vdp_ctrl.o \
|
||||
obj/vdp_render.o \
|
||||
obj/system.o \
|
||||
obj/io_ctrl.o \
|
||||
obj/mem68k.o \
|
||||
obj/memz80.o \
|
||||
obj/membnk.o \
|
||||
obj/state.o
|
||||
|
||||
OBJECTS += obj/sound.o \
|
||||
obj/sn76489.o \
|
||||
|
||||
OBJECTS += obj/input.o \
|
||||
obj/gamepad.o \
|
||||
obj/lightgun.o \
|
||||
obj/mouse.o \
|
||||
obj/activator.o \
|
||||
obj/xe_a1p.o \
|
||||
obj/teamplayer.o \
|
||||
obj/paddle.o \
|
||||
obj/sportspad.o
|
||||
|
||||
|
||||
OBJECTS += obj/sound.o \
|
||||
obj/sn76489.o \
|
||||
obj/ym2612.o
|
||||
|
||||
OBJECTS += obj/Fir_Resampler.o
|
||||
@ -54,7 +64,8 @@ OBJECTS += obj/sram.o \
|
||||
obj/ssp16.o \
|
||||
obj/ggenie.o \
|
||||
obj/areplay.o \
|
||||
obj/cart_hw.o
|
||||
obj/md_cart.o \
|
||||
obj/sms_cart.o
|
||||
|
||||
OBJECTS += obj/main.o \
|
||||
obj/config.o \
|
||||
@ -84,6 +95,9 @@ obj/%.o : ../sound/%.c ../sound/%.h
|
||||
obj/%.o : ../sound/%.c
|
||||
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||
|
||||
obj/%.o : ../input_hw/%.c ../input_hw/%.h
|
||||
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||
|
||||
obj/%.o : ../cart_hw/%.c ../cart_hw/%.h
|
||||
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
|
||||
|
||||
|
@ -28,7 +28,7 @@ void set_config_defaults(void)
|
||||
config.force_dtack = 0;
|
||||
config.addr_error = 1;
|
||||
config.tmss = 0;
|
||||
config.lock_on = 0;
|
||||
config.lock_on = 0;//TYPE_SK;
|
||||
config.romtype = 0;
|
||||
|
||||
/* display options */
|
||||
@ -36,13 +36,13 @@ void set_config_defaults(void)
|
||||
config.render = 0;
|
||||
|
||||
/* controllers options */
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_GAMEPAD;
|
||||
input.system[0] = SYSTEM_MD_GAMEPAD;
|
||||
input.system[1] = SYSTEM_MD_GAMEPAD;
|
||||
config.gun_cursor[0] = 1;
|
||||
config.gun_cursor[1] = 1;
|
||||
config.invert_mouse = 0;
|
||||
for (i=0;i<MAX_INPUTS;i++)
|
||||
{
|
||||
config.input[i].padtype = DEVICE_3BUTTON;
|
||||
config.input[i].padtype = DEVICE_PAD6B;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ uint8 *load_archive(char *filename, int *file_size)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ret = unzGetCurrentFileInfo(fd, &info, NULL, 0, NULL, 0, NULL, 0);
|
||||
ret = unzGetCurrentFileInfo(fd, &info, filename, 128, NULL, 0, NULL, 0);
|
||||
if(ret != UNZ_OK)
|
||||
{
|
||||
unzClose(fd);
|
||||
|
@ -10,7 +10,7 @@
|
||||
#define SOUND_FREQUENCY 48000
|
||||
#define SOUND_SAMPLES_SIZE 2048
|
||||
|
||||
#define VIDEO_WIDTH 320
|
||||
#define VIDEO_WIDTH 320
|
||||
#define VIDEO_HEIGHT 240
|
||||
|
||||
int joynum = 0;
|
||||
@ -362,11 +362,15 @@ static int sdl_control_update(SDLKey keystate)
|
||||
}
|
||||
|
||||
/* reinitialize VC max value */
|
||||
vc_max = 0xEA + 24*vdp_pal;
|
||||
if (reg[1] & 8)
|
||||
static const uint16 vc_table[4][2] =
|
||||
{
|
||||
vc_max += (28 - 20*vdp_pal);
|
||||
}
|
||||
/* NTSC, PAL */
|
||||
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||
{0xEA , 0x102}, /* Mode 5 (224 lines) */
|
||||
{0xDA , 0xF2}, /* Mode 4 (192 lines) */
|
||||
{0x106, 0x10A} /* Mode 5 (240 lines) */
|
||||
};
|
||||
vc_max = vc_table[(reg[1] >> 2) & 3][vdp_pal];
|
||||
|
||||
/* reinitialize display area */
|
||||
bitmap.viewport.changed = 3;
|
||||
@ -389,11 +393,11 @@ static int sdl_control_update(SDLKey keystate)
|
||||
|
||||
case SDLK_F12:
|
||||
{
|
||||
while (input.dev[++joynum] == NO_DEVICE)
|
||||
joynum = (joynum + 1) % MAX_DEVICES;
|
||||
while (input.dev[joynum] == NO_DEVICE)
|
||||
{
|
||||
joynum = joynum % MAX_DEVICES;
|
||||
joynum = (joynum + 1) % MAX_DEVICES;
|
||||
}
|
||||
joynum = joynum % MAX_DEVICES;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -412,24 +416,9 @@ static int sdl_control_update(SDLKey keystate)
|
||||
int sdl_input_update(void)
|
||||
{
|
||||
uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
while (input.dev[joynum] == NO_DEVICE)
|
||||
{
|
||||
joynum ++;
|
||||
if (joynum > MAX_DEVICES - 1) joynum = 0;
|
||||
}
|
||||
|
||||
/* reset input */
|
||||
input.pad[joynum] = 0;
|
||||
|
||||
/* keyboard */
|
||||
if(keystate[SDLK_a]) input.pad[joynum] |= INPUT_A;
|
||||
if(keystate[SDLK_s]) input.pad[joynum] |= INPUT_B;
|
||||
if(keystate[SDLK_d]) input.pad[joynum] |= INPUT_C;
|
||||
if(keystate[SDLK_f]) input.pad[joynum] |= INPUT_START;
|
||||
if(keystate[SDLK_z]) input.pad[joynum] |= INPUT_X;
|
||||
if(keystate[SDLK_x]) input.pad[joynum] |= INPUT_Y;
|
||||
if(keystate[SDLK_c]) input.pad[joynum] |= INPUT_Z;
|
||||
if(keystate[SDLK_v]) input.pad[joynum] |= INPUT_MODE;
|
||||
|
||||
switch (input.dev[joynum])
|
||||
{
|
||||
@ -440,13 +429,46 @@ int sdl_input_update(void)
|
||||
int state = SDL_GetMouseState(&x,&y);
|
||||
|
||||
/* Calculate X Y axis values */
|
||||
input.analog[joynum - 4][0] = (x * bitmap.viewport.w) / 640;
|
||||
input.analog[joynum - 4][1] = (y * bitmap.viewport.h) / 480;
|
||||
input.analog[joynum][0] = (x * bitmap.viewport.w) / VIDEO_WIDTH;
|
||||
input.analog[joynum][1] = (y * bitmap.viewport.h) / VIDEO_HEIGHT;
|
||||
|
||||
/* Map mouse buttons to player #1 inputs */
|
||||
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_C;
|
||||
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_B;
|
||||
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A;
|
||||
/* Start,Left,Right,Middle buttons -> 0 0 0 0 START MIDDLE RIGHT LEFT */
|
||||
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
|
||||
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
|
||||
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_A;
|
||||
if(keystate[SDLK_f]) input.pad[joynum] |= INPUT_START;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_PADDLE:
|
||||
{
|
||||
/* get mouse (absolute values) */
|
||||
int x;
|
||||
int state = SDL_GetMouseState(&x, NULL);
|
||||
|
||||
/* Range is [0;256], 128 being middle position */
|
||||
input.analog[joynum][0] = x * 256 /VIDEO_WIDTH;
|
||||
|
||||
/* Button I -> 0 0 0 0 0 0 0 I*/
|
||||
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_SPORTSPAD:
|
||||
{
|
||||
/* get mouse (relative values) */
|
||||
int x,y;
|
||||
int state = SDL_GetRelativeMouseState(&x,&y);
|
||||
|
||||
/* Range is [0;256] */
|
||||
input.analog[joynum][0] = (unsigned char)(-x & 0xFF);
|
||||
input.analog[joynum][1] = (unsigned char)(-y & 0xFF);
|
||||
|
||||
/* Buttons I & II -> 0 0 0 0 0 0 II I*/
|
||||
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
|
||||
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -457,24 +479,82 @@ int sdl_input_update(void)
|
||||
int x,y;
|
||||
int state = SDL_GetRelativeMouseState(&x,&y);
|
||||
|
||||
/* Sega Mouse range is -256;+256 */
|
||||
input.analog[2][0] = x * 2;
|
||||
input.analog[2][1] = y * 2;
|
||||
/* Sega Mouse range is [-256;+256] */
|
||||
input.analog[joynum][0] = x * 2;
|
||||
input.analog[joynum][1] = y * 2;
|
||||
|
||||
/* Vertical movement is upsidedown */
|
||||
if (!config.invert_mouse)
|
||||
input.analog[2][1] = 0 - input.analog[2][1];
|
||||
input.analog[joynum][1] = 0 - input.analog[joynum][1];
|
||||
|
||||
/* Start,Left,Right,Middle buttons -> 0 0 0 0 START MIDDLE RIGHT LEFT */
|
||||
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
|
||||
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
|
||||
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_A;
|
||||
if(keystate[SDLK_f]) input.pad[joynum] |= INPUT_START;
|
||||
|
||||
/* Map mouse buttons to player #1 inputs */
|
||||
if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_C;
|
||||
if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_B;
|
||||
if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_XE_A1P:
|
||||
{
|
||||
/* A,B,C,D,Select,START,E1,E2 buttons -> E1(?) E2(?) START SELECT(?) A B C D */
|
||||
if(keystate[SDLK_a]) input.pad[joynum] |= INPUT_START;
|
||||
if(keystate[SDLK_s]) input.pad[joynum] |= INPUT_A;
|
||||
if(keystate[SDLK_d]) input.pad[joynum] |= INPUT_C;
|
||||
if(keystate[SDLK_f]) input.pad[joynum] |= INPUT_Y;
|
||||
if(keystate[SDLK_z]) input.pad[joynum] |= INPUT_B;
|
||||
if(keystate[SDLK_x]) input.pad[joynum] |= INPUT_X;
|
||||
if(keystate[SDLK_c]) input.pad[joynum] |= INPUT_MODE;
|
||||
if(keystate[SDLK_v]) input.pad[joynum] |= INPUT_Z;
|
||||
|
||||
/* Left Analog Stick (bidirectional) */
|
||||
if(keystate[SDLK_UP]) input.analog[joynum][1]-=2;
|
||||
else if(keystate[SDLK_DOWN]) input.analog[joynum][1]+=2;
|
||||
else input.analog[joynum][1] = 128;
|
||||
if(keystate[SDLK_LEFT]) input.analog[joynum][0]-=2;
|
||||
else if(keystate[SDLK_RIGHT]) input.analog[joynum][0]+=2;
|
||||
else input.analog[joynum][0] = 128;
|
||||
|
||||
/* Right Analog Stick (unidirectional) */
|
||||
if(keystate[SDLK_KP8]) input.analog[joynum+1][0]-=2;
|
||||
else if(keystate[SDLK_KP2]) input.analog[joynum+1][0]+=2;
|
||||
else if(keystate[SDLK_KP4]) input.analog[joynum+1][0]-=2;
|
||||
else if(keystate[SDLK_KP6]) input.analog[joynum+1][0]+=2;
|
||||
else input.analog[joynum+1][0] = 128;
|
||||
|
||||
/* Limiters */
|
||||
if (input.analog[joynum][0] > 0xFF) input.analog[joynum][0] = 0xFF;
|
||||
else if (input.analog[joynum][0] < 0) input.analog[joynum][0] = 0;
|
||||
if (input.analog[joynum][1] > 0xFF) input.analog[joynum][1] = 0xFF;
|
||||
else if (input.analog[joynum][1] < 0) input.analog[joynum][1] = 0;
|
||||
if (input.analog[joynum+1][0] > 0xFF) input.analog[joynum+1][0] = 0xFF;
|
||||
else if (input.analog[joynum+1][0] < 0) input.analog[joynum+1][0] = 0;
|
||||
if (input.analog[joynum+1][1] > 0xFF) input.analog[joynum+1][1] = 0xFF;
|
||||
else if (input.analog[joynum+1][1] < 0) input.analog[joynum+1][1] = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_ACTIVATOR:
|
||||
{
|
||||
if(keystate[SDLK_g]) input.pad[joynum] |= INPUT_ACTIVATOR_7L;
|
||||
if(keystate[SDLK_h]) input.pad[joynum] |= INPUT_ACTIVATOR_7U;
|
||||
if(keystate[SDLK_j]) input.pad[joynum] |= INPUT_ACTIVATOR_8L;
|
||||
if(keystate[SDLK_k]) input.pad[joynum] |= INPUT_ACTIVATOR_8U;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if(keystate[SDLK_a]) input.pad[joynum] |= INPUT_A;
|
||||
if(keystate[SDLK_s]) input.pad[joynum] |= INPUT_B;
|
||||
if(keystate[SDLK_d]) input.pad[joynum] |= INPUT_C;
|
||||
if(keystate[SDLK_f]) input.pad[joynum] |= INPUT_START;
|
||||
if(keystate[SDLK_z]) input.pad[joynum] |= INPUT_X;
|
||||
if(keystate[SDLK_x]) input.pad[joynum] |= INPUT_Y;
|
||||
if(keystate[SDLK_c]) input.pad[joynum] |= INPUT_Z;
|
||||
if(keystate[SDLK_v]) input.pad[joynum] |= INPUT_MODE;
|
||||
|
||||
if(keystate[SDLK_UP]) input.pad[joynum] |= INPUT_UP;
|
||||
else
|
||||
if(keystate[SDLK_DOWN]) input.pad[joynum] |= INPUT_DOWN;
|
||||
|
2205
source/vdp_ctrl.c
Normal file
86
source/vdp_ctrl.h
Normal file
@ -0,0 +1,86 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Video Display Processor (68k & Z80 CPU interface)
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _VDP_H_
|
||||
#define _VDP_H_
|
||||
|
||||
/* VDP context */
|
||||
extern uint8 reg[0x20];
|
||||
extern uint8 sat[0x400];
|
||||
extern uint8 vram[0x10000];
|
||||
extern uint8 cram[0x80];
|
||||
extern uint8 vsram[0x80];
|
||||
extern uint8 hint_pending;
|
||||
extern uint8 vint_pending;
|
||||
extern uint8 m68k_irq_state;
|
||||
extern uint16 status;
|
||||
extern uint32 dma_length;
|
||||
|
||||
/* Global variables */
|
||||
extern uint16 ntab;
|
||||
extern uint16 ntbb;
|
||||
extern uint16 ntwb;
|
||||
extern uint16 satb;
|
||||
extern uint16 hscb;
|
||||
extern uint8 bg_name_dirty[0x800];
|
||||
extern uint16 bg_name_list[0x800];
|
||||
extern uint16 bg_list_index;
|
||||
extern uint8 bg_pattern_cache[0x80000];
|
||||
extern uint8 hscroll_mask;
|
||||
extern uint8 playfield_shift;
|
||||
extern uint8 playfield_col_mask;
|
||||
extern uint16 playfield_row_mask;
|
||||
extern uint8 odd_frame;
|
||||
extern uint8 im2_flag;
|
||||
extern uint8 interlaced;
|
||||
extern uint8 vdp_pal;
|
||||
extern uint16 v_counter;
|
||||
extern uint16 vc_max;
|
||||
extern uint16 hscroll;
|
||||
extern uint16 vscroll;
|
||||
extern uint16 lines_per_frame;
|
||||
extern int32 fifo_write_cnt;
|
||||
extern uint32 fifo_lastwrite;
|
||||
extern uint32 hvc_latch;
|
||||
extern const uint8 *hctab;
|
||||
|
||||
/* Function pointers */
|
||||
extern void (*vdp_68k_data_w)(unsigned int data);
|
||||
extern void (*vdp_z80_data_w)(unsigned int data);
|
||||
extern unsigned int (*vdp_68k_data_r)(void);
|
||||
extern unsigned int (*vdp_z80_data_r)(void);
|
||||
|
||||
/* Function prototypes */
|
||||
extern void vdp_init(void);
|
||||
extern void vdp_reset(void);
|
||||
extern int vdp_context_save(uint8 *state);
|
||||
extern int vdp_context_load(uint8 *state, char *version);
|
||||
extern void vdp_dma_update(unsigned int cycles);
|
||||
extern void vdp_68k_ctrl_w(unsigned int data);
|
||||
extern void vdp_z80_ctrl_w(unsigned int data);
|
||||
extern unsigned int vdp_ctrl_r(unsigned int cycles);
|
||||
extern unsigned int vdp_hvc_r(unsigned int cycles);
|
||||
extern void vdp_test_w(unsigned int data);
|
||||
extern int vdp_68k_irq_ack(int int_level);
|
||||
|
||||
#endif /* _VDP_H_ */
|
3705
source/vdp_render.c
Normal file
65
source/vdp_render.h
Normal file
@ -0,0 +1,65 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus
|
||||
* Video Display Processor (Mode 4 & Mode 5 rendering)
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
||||
* Eke-Eke (2007-2011), additional code & fixes for the GCN/Wii port
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _RENDER_H_
|
||||
#define _RENDER_H_
|
||||
|
||||
/* Global variables */
|
||||
extern uint8 object_count;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void render_init(void);
|
||||
extern void render_reset(void);
|
||||
extern void render_line(int line);
|
||||
extern void blank_line(int line, int offset, int width);
|
||||
extern void remap_line(int line);
|
||||
extern void window_clip(unsigned int data, unsigned int sw);
|
||||
extern void render_bg_m4(int line, int width);
|
||||
extern void render_bg_m5(int line, int width);
|
||||
extern void render_bg_m5_vs(int line, int width);
|
||||
extern void render_bg_m5_im2(int line, int width);
|
||||
extern void render_bg_m5_im2_vs(int line, int width);
|
||||
extern void render_obj_m4(int max_width);
|
||||
extern void render_obj_m5(int max_width);
|
||||
extern void render_obj_m5_ste(int max_width);
|
||||
extern void render_obj_m5_im2(int max_width);
|
||||
extern void render_obj_m5_im2_ste(int max_width);
|
||||
extern void parse_satb_m4(int line);
|
||||
extern void parse_satb_m5(int line);
|
||||
extern void update_bg_pattern_cache_m4(int index);
|
||||
extern void update_bg_pattern_cache_m5(int index);
|
||||
#ifdef NGC
|
||||
extern void color_update(int index, unsigned int data);
|
||||
#endif
|
||||
|
||||
/* Function pointers */
|
||||
extern void (*render_bg)(int line, int width);
|
||||
extern void (*render_obj)(int max_width);
|
||||
extern void (*parse_satb)(int line);
|
||||
extern void (*update_bg_pattern_cache)(int index);
|
||||
#ifndef NGC
|
||||
extern void (*color_update)(int index, unsigned int data);
|
||||
#endif
|
||||
|
||||
#endif /* _RENDER_H_ */
|
||||
|
@ -1,27 +1,26 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Define size independent data types and operations. *
|
||||
* *
|
||||
* The following types must be supported by all platforms: *
|
||||
* *
|
||||
* UINT8 - Unsigned 8-bit Integer INT8 - Signed 8-bit integer *
|
||||
* UINT16 - Unsigned 16-bit Integer INT16 - Signed 16-bit integer *
|
||||
* UINT32 - Unsigned 32-bit Integer INT32 - Signed 32-bit integer *
|
||||
* UINT64 - Unsigned 64-bit Integer INT64 - Signed 64-bit integer *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* Define size independent data types and operations. *
|
||||
* *
|
||||
* The following types must be supported by all platforms: *
|
||||
* *
|
||||
* UINT8 - Unsigned 8-bit Integer INT8 - Signed 8-bit integer *
|
||||
* UINT16 - Unsigned 16-bit Integer INT16 - Signed 16-bit integer *
|
||||
* UINT32 - Unsigned 32-bit Integer INT32 - Signed 32-bit integer *
|
||||
* UINT64 - Unsigned 64-bit Integer INT64 - Signed 64-bit integer *
|
||||
* *
|
||||
* *
|
||||
* The macro names for the artithmatic operations are composed as follows: *
|
||||
* *
|
||||
* XXX_R_A_B, where XXX - 3 letter operation code (ADD, SUB, etc.) *
|
||||
* R - The type of the result *
|
||||
* A - The type of operand 1 *
|
||||
* B - The type of operand 2 (if binary operation) *
|
||||
* *
|
||||
* Each type is one of: U8,8,U16,16,U32,32,U64,64 *
|
||||
* *
|
||||
* *
|
||||
* XXX_R_A_B, where XXX - 3 letter operation code (ADD, SUB, etc.) *
|
||||
* R - The type of the result *
|
||||
* A - The type of operand 1 *
|
||||
* B - The type of operand 2 (if binary operation) *
|
||||
* *
|
||||
* Each type is one of: U8,8,U16,16,U32,32,U64,64 *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef OSD_CPU_H
|
||||
#define OSD_CPU_H
|
||||
|
||||
@ -52,6 +51,7 @@ __extension__ typedef signed long long INT64;
|
||||
* thus PAIR.d can be used to pass arguments to the memory system
|
||||
* which expects 'int' really.
|
||||
******************************************************************************/
|
||||
|
||||
typedef union {
|
||||
#ifdef LSB_FIRST
|
||||
struct { UINT8 l,h,h2,h3; } b;
|
||||
|