[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.
This commit is contained in:
ekeeke31 2011-03-31 22:11:05 +00:00
parent f34b8d4557
commit ab4638144c
101 changed files with 16328 additions and 4588 deletions

View File

@ -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)
---------------------------------------------------------------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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)*/

View File

@ -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

File diff suppressed because it is too large Load Diff

75
source/cart_hw/md_cart.h Normal file
View 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
View 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
View 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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View 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

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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
}

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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 */

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -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();

View File

@ -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()

View File

@ -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
View 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);
}

View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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);
}

View 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

View 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);
}

View 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
View 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
View 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
View 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
View 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_ */

View File

@ -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;
}

View File

@ -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 ============================== */

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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];
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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_ */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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__

View File

@ -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);
}
}

View File

@ -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_ */

View File

@ -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));

View File

@ -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;

View File

@ -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_ */

View File

@ -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;

View File

@ -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); \

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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 $@

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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

File diff suppressed because it is too large Load Diff

86
source/vdp_ctrl.h Normal file
View 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

File diff suppressed because it is too large Load Diff

65
source/vdp_render.h Normal file
View 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_ */

View File

@ -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;

File diff suppressed because it is too large Load Diff

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