#include <clip.h>

#define AY38914_CLOCK	(NTSC_COLOR_SUBCARRIER/2)
#define AY38914BUFLEN	320

/////////////////////////////////////////////////////////////////////////////
#define DIR "C:/Home/Share/intv/roms/"
#define EXEC "exec.bin"
#define GROM "grom.bin"
//#define ROM "examples/balls1.bin"
//#define ROM "examples/balls2.bin"
//#define ROM "examples/bankdemo.bin"
//#define ROM "examples/banktest.bin"
//#define ROM "examples/bankworld.bin"
//#define ROM "examples/bncpix.bin"
//#define ROM "examples/csumexec.bin"
//#define ROM "examples/gram_scroll.bin"
//#define ROM "examples/gram_scroll2.bin"
//#define ROM "examples/handdemo.bin"
//#define ROM "examples/hello.bin"
//#define ROM "examples/life.bin"
//#define ROM "examples/mazedemo.bin"
//#define ROM "examples/mem_test.bin"
//#define ROM "examples/mob_test.bin"
//#define ROM "examples/tagalong.bin"
//#define ROM "examples/tagalong2.bin"
//#define ROM "examples/tagalong2b.bin"
//#define ROM "examples/world.bin"
//#define ROM "ABPA_Backgammon_(1978)_(Mattel).bin"
//#define ROM "Advanced_D&D_-_Treasure_of_Tarmin_(1982)_(Mattel).bin"
//#define ROM "Advanced_Dungeons_and_Dragons_(1982)_(Mattel).bin"
//#define ROM "Adventure_(AD&D_-_Cloudy_Mountain)_(1982)_(Mattel).bin"
//#define ROM "Air_Strike_(1982)_(Mattel).bin"
//#define ROM "All-Star_Major_League_Baseball_(1983)_(Mattel).bin"
//#define ROM "Armor_Battle_(1978)_(Mattel).bin"
#define ROM "Astrosmash_(1981)_(Mattel).bin"
//#define ROM "Astrosmash_-_Meteor_(1981)_(Mattel).bin"
//#define ROM "Atlantis_(1981)_(Imagic)_[!].bin"
//#define ROM "Auto_Racing_(1979)_(Mattel).bin"
//#define ROM "B-17_Bomber_(1981)_(Mattel)_[!].bin"
//#define ROM "Baseball_(1978)_(Mattel).bin"
//#define ROM "BeamRider_(1983)_(Activision)_[!].bin"
//#define ROM "Beauty_and_the_Beast_(1982)_(Imagic)_[!].bin"
//#define ROM "Blockade_Runner_(1983)_(Interphase).bin"
//#define ROM "Body_Slam_-_Super_Pro_Wrestling_(1988)_(Intv_Corp).bin"
//#define ROM "Bomb_Squad_(1982)_(Mattel)_[!].bin"
//#define ROM "Boxing_(1980)_(Mattel).bin"
//#define ROM "Brickout!_(1981)_(Mattel).bin"
//#define ROM "Bump_'N'_Jump_(1982-83)_(Mattel).bin"
//#define ROM "BurgerTime!_(1982)_(Mattel).bin"
//#define ROM "Buzz_Bombers_(1982)_(Mattel).bin"
//#define ROM "Carnival_(1982)_(Coleco-CBS).bin"
//#define ROM "Centipede_(1983)_(Atarisoft).bin"
//#define ROM "Championship_Tennis_(1985)_(Mattel).bin"
//#define ROM "Checkers_(1979)_(Mattel).bin"
//#define ROM "Chip_Shot_-_Super_Pro_Golf_(1987)_(Intv_Corp).bin"
//#define ROM "Commando_(1987)_(Mattel).bin"
//#define ROM "Congo_Bongo_(1983)_(Sega).bin"
//#define ROM "Deep_Pockets-Super_Pro_Pool_and_Billiards_(1990)_(Realtime)_[!].bin"
//#define ROM "Defender_(1983)_(Atarisoft).bin"
//#define ROM "Demon_Attack_(1982)_(Imagic)_[!].bin"
//#define ROM "Dig_Dug_(1987)_(Intv_Corp).bin"
//#define ROM "Diner_(1987)_(Intv_Corp).bin"
//#define ROM "Donkey_Kong_(1982)_(Coleco).bin"
//#define ROM "Donkey_Kong_Jr_(1982)_(Coleco).bin"
//#define ROM "Doom_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "Dracula_(1982)_(Imagic)_[!].bin"
//#define ROM "Dragonfire_(1982)_(Imagic)_[!].bin"
//#define ROM "Dreadnaught_Factor,_The_(1983)_(Activision)_[!].bin"
//#define ROM "Dreadnaught_Factor,_The_(1983)_(Activision)_[a1].bin"
//#define ROM "Dreadnaught_Factor,_The_(Prototype)_(1983)_(Activision).bin"
//#define ROM "Duncan's_Thin_Ice_(1983)_(Mattel).bin"
//#define ROM "Easter_Eggs_(1981)_(Mattel).bin"
//#define ROM "Electric_Company_-_Math_Fun_(1978)_(CTW).bin"
//#define ROM "Electric_Company_-_Word_Fun_(1980)_(CTW).bin"
//#define ROM "Entertainment_Computer_System_EXEC-BASIC_(1978)_(Mattel)_[!].bin"
//#define ROM "Executive_ROM,_The_(1978)_(Mattel).bin"
//#define ROM "Fathom_(1983)_(Imagic)_[!].bin"
//#define ROM "Frogger_(1983)_(Parker_Bros).bin"
//#define ROM "Frog_Bog_(1982)_(Mattel).bin"
//#define ROM "Go_For_the_Gold_(1981)_(Mattel).bin"
//#define ROM "Grid_Shock_(1982)_(Mattel).bin"
//#define ROM "GROM,_The_(1978)_(General_Instruments)_[!].bin"
//#define ROM "Happy_Trails_(1983)_(Activision).bin"
//#define ROM "Hard_Hat_(1979)_(Mattel).bin"
//#define ROM "Horse_Racing_(1980)_(Mattel).bin"
//#define ROM "Hover_Force_(1986)_(Intv_Corp).bin"
//#define ROM "Hypnotic_Lights_(1981)_(Mattel).bin"
//#define ROM "Ice_Trek_(1983)_(Imagic)_[!].bin"
//#define ROM "IntelliVoice_BIOS_(1981)_(Mattel).bin"
//#define ROM "INTV_-_Intelligent_TV_Demo_#1682_(Prototype)_(1978)_(Mattel).bin"
//#define ROM "INTV_-_Intelligent_TV_Demo_#5853_(1983)_(Mattel).bin"
//#define ROM "INTV_-_Intelligent_TV_Demo_#5932_Revised_(1978)_(Mattel).bin"
//#define ROM "INTV_-_Intelligent_TV_Demo_(1978)_(Mattel).bin"
//#define ROM "INTV_-_Intelligent_TV_Demo_Intl._#5859_(1982)_(Mattel).bin"
//#define ROM "Jetsons,_The_-_Ways_With_Words_(1983)_(Mattel).bin"
//#define ROM "King_of_the_Mountain_(1982)_(Mattel).bin"
//#define ROM "Kool-Aid_Man_(1983)_(Mattel).bin"
//#define ROM "Lady_Bug_(1983)_(Coleco).bin"
//#define ROM "Land_Battle_(1982)_(Mattel).bin"
//#define ROM "Las_Vegas_Blackjack_and_Poker_(1979)_(Mattel).bin"
//#define ROM "Las_Vegas_Roulette_(1979)_(Mattel).bin"
//#define ROM "League_of_Light_(Prototype)_(1983)_(Activision)_[a2].bin"
//#define ROM "Learning_Fun_II_-_Word_Wizard_Memory_Fun_(1987)_(Intv_Corp).bin"
//#define ROM "Learning_Fun_I_-_Math_Master_Factor_Fun_(1987)_(Intv_Corp).bin"
//#define ROM "Lock_'N'_Chase_(1982)_(Mattel).bin"
//#define ROM "Loco-Motion_(1982)_(Mattel).bin"
//#define ROM "Masters_of_the_Universe-The_Power_of_He-Man!_(1983)_(Mattel).bin"
//#define ROM "Melody_Blaster_(1983)_(Mattel)_[!].bin"
//#define ROM "Microsurgeon_(1982)_(Imagic)_[!].bin"
//#define ROM "Mind_Strike!_(1982)_(Mattel)_[!].bin"
//#define ROM "Minehunter_Beta3_(2003)_(Ryan_Kinnen).bin"
//#define ROM "Minotaur_(1981)_(Mattel).bin"
//#define ROM "Minotaur_(Treasure_of_Tarmin_Hack)_(1982)_(Mattel).bin"
//#define ROM "Minotaur_V1.1_(1981)_(Mattel)_[!].bin"
//#define ROM "Mission_X_(1982)_(Mattel).bin"
//#define ROM "MOB_Collision_Test_(2002)_(Arnauld_Chevallier).bin"
//#define ROM "Motocross_(1982)_(Mattel).bin"
//#define ROM "Mountain_Madness_-_Super_Pro_Skiing_(1987)_(Intv_Corp).bin"
//#define ROM "Mouse_Trap_(1982)_(Coleco).bin"
//#define ROM "MTE201_Intellivision_Test_Cartridge_(1978)_(Mattel).bin"
//#define ROM "NASL_Soccer_(1979)_(Mattel).bin"
//#define ROM "NBA_Basketball_(1978)_(Mattel).bin"
//#define ROM "NFL_Football_(1978)_(Mattel).bin"
//#define ROM "NHL_Hockey_(1979)_(Mattel).bin"
//#define ROM "Night_Stalker_(1982)_(Mattel).bin"
//#define ROM "Nova_Blast_(1983)_(Imagic)_[!].bin"
//#define ROM "Number_Jumble_(1983)_(Mattel)_[!].bin"
//#define ROM "Pac-Man_(1983)_(Atarisoft).bin"
//#define ROM "Pac-Man_(1983)_(Intv_Corp).bin"
//#define ROM "PBA_Bowling_(1980)_(Mattel).bin"
//#define ROM "PGA_Golf_(1979)_(Mattel).bin"
//#define ROM "Pinball_(1981)_(Mattel).bin"
//#define ROM "Pitfall!_(1982)_(Activision)_[!].bin"
//#define ROM "Pole_Position_(1986)_(Intv_Corp).bin"
//#define ROM "Popeye_(1983)_(Parker_Bros).bin"
//#define ROM "PSG_Tinkerer_(2002)_(Ryan_Kinnen).bin"
//#define ROM "Q-bert_(1983)_(Parker_Bros).bin"
//#define ROM "Reversi_(1984)_(Mattel).bin"
//#define ROM "River_Raid_(1982-83)_(Activision)_[!].bin"
//#define ROM "Robot_Rubble_V1_(Prototype)_(1983)_(Activision).bin"
//#define ROM "Robot_Rubble_V2_(Prototype)_(1983)_(Activision).bin"
//#define ROM "Royal_Dealer_(1981)_(Mattel).bin"
//#define ROM "Safecracker_(1983)_(Imagic)_[!].bin"
//#define ROM "Santa's_Helper_(1983)_(Mattel).bin"
//#define ROM "Scooby_Doo's_Maze_Chase_(1983)_(Mattel).bin"
//#define ROM "SDK-1600_Bouncing_Pixels_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_GRAM-Based_Scrolling_Demo#1_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_GRAM-Based_Scrolling_Demo#2_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Hand_Controller_Scanning_Demo_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Hello_World_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Intellicart_Bankswitched_Memory_Test_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Intellicart_Bankswitched_Spinning_World_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Intellicart_Bankswitching_Demo_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Intellicart_Memory_Test_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_John_Conway's_Life_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Maze_Demo_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Movable_Object_Demo_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Psycho_Balls_#1_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Psycho_Balls_#2_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_ROM_Checksummer_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Spinning_World_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Tag-Along_Todd_#1_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Tag-Along_Todd_#2a_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "SDK-1600_Tag-Along_Todd_#2b_(2002)_(Joseph_Zbiciak).bin"
//#define ROM "Sears_Super_Video_Arcade_BIOS_(1978)_(Sears)_[!].bin"
//#define ROM "Sea_Battle_(1980)_(Mattel).bin"
//#define ROM "Sewer_Sam_(1983)_(Interphase).bin"
//#define ROM "Shark!_Shark!_(1982)_(Mattel)_[!].bin"
//#define ROM "Shark!_Shark!_(1982)_(Mattel)_[a1].bin"
//#define ROM "Sharp_Shot_(1982)_(Mattel).bin"
//#define ROM "Slam_Dunk_-_Super_Pro_Basketball_(1987)_(Intv_Corp).bin"
//#define ROM "Slap_Shot_-_Super_Pro_Hockey_(1987)_(Intv_Corp).bin"
//#define ROM "Snafu_(1981)_(Mattel).bin"
//#define ROM "Space_Armada_(1981)_(Mattel).bin"
//#define ROM "Space_Battle_(1979)_(Mattel).bin"
//#define ROM "Space_Cadet_(1982)_(Mattel).bin"
//#define ROM "Space_Hawk_(1981)_(Mattel).bin"
//#define ROM "Space_Spartans_(1981)_(Mattel)_[!].bin"
//#define ROM "Spiker!_-_Super_Pro_Volleyball_(1988)_(Intv_Corp).bin"
//#define ROM "Stadium_Mud_Buggies_(1988)_(Intv_Corp).bin"
//#define ROM "Stampede_(1982)_(Activision)_[!].bin"
//#define ROM "Star_Strike_(1981)_(Mattel).bin"
//#define ROM "Star_Wars_-_The_Empire_Strikes_Back_(1983)_(Parker_Bros).bin"
//#define ROM "Street_(1981)_(Mattel).bin"
//#define ROM "Sub_Hunt_(1981)_(Mattel).bin"
//#define ROM "Super_Cobra_(1983)_(Konami).bin"
//#define ROM "Super_Masters!_(1982)_(Mattel).bin"
//#define ROM "Super_Pro_Decathlon_(1988)_(Intv_Corp).bin"
//#define ROM "Super_Pro_Football_(1986)_(Intv_Corp).bin"
//#define ROM "Super_Soccer_(1983)_(Mattel).bin"
//#define ROM "Swords_and_Serpents_(1982)_(Imagic)_[!].bin"
//#define ROM "Takeover_(1982)_(Mattel).bin"
//#define ROM "Tennis_(1980)_(Mattel).bin"
//#define ROM "Thunder_Castle_(1982)_(Mattel).bin"
//#define ROM "Tower_of_Doom_(1986)_(Intv_Corp).bin"
//#define ROM "Triple_Action_(1981)_(Mattel).bin"
//#define ROM "Triple_Challenge_(1986)_(Intv_Corp).bin"
//#define ROM "TRON_-_Deadly_Discs_(1981)_(Mattel).bin"
//#define ROM "TRON_-_Deadly_Discs_-_Deadly_Dogs_(1987)_(Intv_Corp).bin"
//#define ROM "TRON_-_Maze-A-Tron_(1981)_(Mattel).bin"
//#define ROM "TRON_-_Solar_Sailer_(1982)_(Mattel).bin"
//#define ROM "Tropical_Trouble_(1982)_(Imagic)_[!].bin"
//#define ROM "Truckin'_(1983)_(Imagic)_[!].bin"
//#define ROM "Turbo_(1983)_(Coleco).bin"
//#define ROM "Tutankham_(1983)_(Parker_Bros).bin"
//#define ROM "U.S._Ski_Team_Skiing_(1980)_(Mattel).bin"
//#define ROM "USCF_Chess_(1981)_(Mattel).bin"
//#define ROM "Utopia_(1981)_(Mattel).bin"
//#define ROM "Vectron_(1982)_(Mattel).bin"
//#define ROM "Venture_(1982)_(Coleco).bin"
//#define ROM "White_Water!_(1983)_(Imagic)_[!].bin"
//#define ROM "World_Cup_Football_(1985)_(Nice_Ideas).bin"
//#define ROM "Worm_Whomper_(1983)_(Activision)_[!].bin"
//#define ROM "Zaxxon_(1982)_(Coleco).bin"
/////////////////////////////////////////////////////////////////////////////
#define APPNAME	"INTVWIN"
#define WIDTH	160
#define HEIGHT	96
#define SCALE	2
unsigned char xbuff[WIDTH * HEIGHT];
int INPUT;
/////////////////////////////////////////////////////////////////////////////
				/* $0000-$003F	STIC			*/
				/* $0040-$00FF	(blank)			*/
///unsigned char  ram1[0x00f0];	/* $0100-$01EF	Scratchpad RAM	 8bit	*/
unsigned char  ram1[0x0100];	/* $0100-$01EF	Scratchpad RAM	 8bit	*/
				/* $01F0-$01FF	PSG			*/
unsigned short ram2[0x0160];	/* $0200-$035F	System RAM	16bit	*/
				/* $0360-$0FFF	(blank)			*/
unsigned short exec[0x1000];	/* $1000-$1FFF	EXEC ROM	10bit	*/
				/* $2000-$2FFF	(blank)			*/
unsigned char  gmem[0x0a00];	/* $3000-$39FF	GROM / GRAM	 8bit	*/
				/* $3A00-$4FFF	(blank)			*/
unsigned short cart[0x1000];	/* $5000-$5FFF	Cartridge ROM	10bit	*/
				/* $6000-$FFFF	(blank)			*/
/////////////////////////////////////////////////////////////////////////////
#define NWHDR		8	/* これ以上増やすとwaveOutWriteでエラーになるみたい */
HWAVEOUT g_wout;
WAVEFORMATEX g_fmt;
WAVEHDR g_whdr[NWHDR];
short g_wbuff[NWHDR][AY38914BUFLEN];
CRITICAL_SECTION snd_cs;
AY38910 ay38910;
void CALLBACK
waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
	static int I;
	int retval;

	if(uMsg != WOM_DONE) return;

	EnterCriticalSection(&snd_cs);
	ay38910_mix(&ay38910, g_wbuff[I], AY38914BUFLEN);
	LeaveCriticalSection(&snd_cs);

	retval = waveOutWrite(hwo, &g_whdr[I], sizeof g_whdr[I]);
	assert(retval == 0);

	I = (I + 1) % NWHDR;
}
void
InitSnd()
{
	int retval;
	int i;

	InitializeCriticalSection(&snd_cs);

	/* init stream */
	memset(&g_fmt, 0, sizeof g_fmt);
	g_fmt.wFormatTag = WAVE_FORMAT_PCM;
	g_fmt.nChannels = 1;
	g_fmt.nSamplesPerSec = 16000;
	g_fmt.nAvgBytesPerSec = 16000 * 2;
	g_fmt.nBlockAlign = 2;
	g_fmt.wBitsPerSample = 16;
	retval = waveOutOpen(&g_wout, WAVE_MAPPER, &g_fmt, (DWORD)waveOutProc, 0, CALLBACK_FUNCTION);
	assert(retval == 0);
	for(i = 0; i < NWHDR; i++) {
		memset(&g_whdr[i], 0, sizeof g_whdr[i]);
		g_whdr[i].lpData = (char*)g_wbuff[i];
		g_whdr[i].dwBufferLength = sizeof g_wbuff[i];
		retval = waveOutPrepareHeader(g_wout, &g_whdr[i], sizeof g_whdr[i]);
		assert(retval == 0);
	}

	/* start playing */
	for(i = 0; i < NWHDR; i++) {
		retval = waveOutWrite(g_wout, &g_whdr[i], sizeof g_whdr[i]);
		assert(retval == 0);
	}
}
/* AY-3-8914のアドレスオフセットから、AY-3-8910のポート番号への変換表 */
const unsigned char psg_map[16] = {
	 0,	/* Channel A Tone Period (Fine Tune) */
	 2,	/* Channel B Tone Period (Fine Tune) */
	 4,	/* Channel C Tone Period (Fine Tune) */
	11,	/* Envelope Period (Fine Tune) */
	 1,	/* Channel A Tone Period (Coarse Tune) */
	 3,	/* Channel B Tone Period (Coarse Tune) */
	 5,	/* Channel C Tone Period (Coarse Tune) */
	12,	/* Envelope Period (Coarse Tune) */
	 7,	/* #Enable */
	 6,	/* Noise Period */
	13,	/* Envelope Shape Cycle */
	 8,	/* Channel A Amplitude */
	 9,	/* Channel B Amplitude */
	10,	/* Channel C Amplitude */
	14,	/* I/O Port A Data Store */
	15,	/* I/O Port B Data Store */
};
int
ay38914_read(int addr)
{
	int data;
	ASSERT((addr >= 0) && (addr <= 0x0f));

	addr = psg_map[addr];
	EnterCriticalSection(&snd_cs);
	ay38910_address(&ay38910, addr);
	data= ay38910_read(&ay38910);
	LeaveCriticalSection(&snd_cs);
	return data;
}
void
ay38914_write(int addr, int data)
{
	ASSERT((addr >= 0) && (addr <= 0x0f));
	ASSERT((data >= 0) && (addr <= 0xff));

	addr = psg_map[addr];
	EnterCriticalSection(&snd_cs);
	ay38910_address(&ay38910, addr);
	ay38910_write(&ay38910, (unsigned char)data);
	LeaveCriticalSection(&snd_cs);
}
unsigned char
ay38910_in(AY38910* ay38910, int port)
{
	ASSERT((port >= 0) && (port <= 1));

	return ram1[0xfe + port];
}
void
ay38910_out(AY38910* ay38910, int port, unsigned char data)
{
	/** no job **/
}
/////////////////////////////////////////////////////////////////////////////
BITMAPINFO* pBMI;
HWND MainWnd;
LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CHAR:
		if(wParam == 'q') {
			DestroyWindow(hWnd);
			return 0;
		}
		return 0;
	case WM_KEYDOWN:
		switch(wParam) {
		case VK_UP:	INPUT |= INTV_KEY_UP;		break;
		case VK_DOWN:	INPUT |= INTV_KEY_DOWN;		break;
		case VK_LEFT:	INPUT |= INTV_KEY_LEFT;		break;
		case VK_RIGHT:	INPUT |= INTV_KEY_RIGHT;	break;
		case '0':	INPUT |= INTV_KEY_0;		break;
		case '1':	INPUT |= INTV_KEY_1;		break;
		case '2':	INPUT |= INTV_KEY_2;		break;
		case '3':	INPUT |= INTV_KEY_3;		break;
		case '4':	INPUT |= INTV_KEY_4;		break;
		case '5':	INPUT |= INTV_KEY_5;		break;
		case '6':	INPUT |= INTV_KEY_6;		break;
		case '7':	INPUT |= INTV_KEY_7;		break;
		case '8':	INPUT |= INTV_KEY_8;		break;
		case '9':	INPUT |= INTV_KEY_9;		break;
		case VK_RETURN:	INPUT |= INTV_KEY_ENTER;	break;
		case VK_BACK:	INPUT |= INTV_KEY_CLEAR;	break;
		case 'Z':	INPUT |= INTV_KEY_ACTION_LEFT;	break;
		case 'X':	INPUT |= INTV_KEY_ACTION_TOP;	break;
		case 'C':	INPUT |= INTV_KEY_ACTION_RIGHT;	break;
		}
		return 0;
	case WM_KEYUP:
		switch(wParam) {
		case VK_UP:	INPUT &=~INTV_KEY_UP;		break;
		case VK_DOWN:	INPUT &=~INTV_KEY_DOWN;		break;
		case VK_LEFT:	INPUT &=~INTV_KEY_LEFT;		break;
		case VK_RIGHT:	INPUT &=~INTV_KEY_RIGHT;	break;
		case '0':	INPUT &=~INTV_KEY_0;		break;
		case '1':	INPUT &=~INTV_KEY_1;		break;
		case '2':	INPUT &=~INTV_KEY_2;		break;
		case '3':	INPUT &=~INTV_KEY_3;		break;
		case '4':	INPUT &=~INTV_KEY_4;		break;
		case '5':	INPUT &=~INTV_KEY_5;		break;
		case '6':	INPUT &=~INTV_KEY_6;		break;
		case '7':	INPUT &=~INTV_KEY_7;		break;
		case '8':	INPUT &=~INTV_KEY_8;		break;
		case '9':	INPUT &=~INTV_KEY_9;		break;
		case VK_RETURN:	INPUT &=~INTV_KEY_ENTER;	break;
		case VK_BACK:	INPUT &=~INTV_KEY_CLEAR;	break;
		case 'Z':	INPUT &=~INTV_KEY_ACTION_LEFT;	break;
		case 'X':	INPUT &=~INTV_KEY_ACTION_TOP;	break;
		case 'C':	INPUT &=~INTV_KEY_ACTION_RIGHT;	break;
		}
		return 0;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}
int
DoMsg()
{
	MSG msg;
	while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
		if(msg.message == WM_QUIT) {
			return 0;
		}
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 1;
}
void
InitUI()
{
	int i;
	BITMAPINFOHEADER* bi;
	RGBQUAD* rgb;
	HINSTANCE hInst;
	WNDCLASS wc;
	RECT rcWin;
	RECT rcCli;
	int ncW;
	int ncH;

	pBMI = (BITMAPINFO*)calloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256, 1);
	bi = &pBMI->bmiHeader;
	rgb = &pBMI->bmiColors[0];
	bi->biSize = sizeof(BITMAPINFOHEADER);
#ifdef STIC_GRAYSCALE
	bi->biWidth = 128;
	bi->biHeight = -88;
#else /*STIC_GRAYSCALE*/
	bi->biWidth = WIDTH;
	bi->biHeight = -HEIGHT;
#endif /*STIC_GRAYSCALE*/
	bi->biPlanes = 1;
	bi->biBitCount = 8;
#ifdef STIC_GRAYSCALE
	for(i = 0; i < 16; i++) {
		rgb[i].rgbRed   = 255 - (255 * i / 15);
		rgb[i].rgbGreen = 255 - (255 * i / 15);
		rgb[i].rgbBlue  = 255 - (255 * i / 15);
	}
#else /*STIC_GRAYSCALE*/
	for(i = 0; i < 16; i++) {
		rgb[i].rgbRed   = stic_color_table[i][0];
		rgb[i].rgbGreen = stic_color_table[i][1];
		rgb[i].rgbBlue  = stic_color_table[i][2];
	}
#endif /*STIC_GRAYSCALE*/

	hInst = GetModuleHandle(NULL);
	//
	memset(&wc, 0, sizeof wc);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.hInstance = hInst;
	wc.hCursor = LoadCursor(NULL, IDC_CROSS);
	wc.lpszClassName = APPNAME;
	RegisterClass(&wc);
	//
	MainWnd = CreateWindow(APPNAME, APPNAME,
		WS_OVERLAPPED,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInst, NULL);
	//
	GetWindowRect(MainWnd, &rcWin);
	GetClientRect(MainWnd, &rcCli);
	ncW = (rcWin.right - rcWin.left) - (rcCli.right - rcCli.left);
	ncH = (rcWin.bottom - rcWin.top) - (rcCli.bottom - rcCli.top);
	MoveWindow(MainWnd, 0, 0,
		ncW + bi->biWidth  * SCALE,
		ncH - bi->biHeight * SCALE, 0);
	//
	ShowWindow(MainWnd, SW_SHOW);
	UpdateWindow(MainWnd);
}
/////////////////////////////////////////////////////////////////////////////
void
InitROM(const char* fname)
{
	FILE* fp;
	int i;
	int hi;
	int lo;

	//-------------------------------------------------------------------
	fp = fopen(DIR EXEC, "rb");
	if(!fp) DIE();
	for(i = 0; i < 0x1000; i++) {
		hi = fgetc(fp);
		lo = fgetc(fp);
		if((hi == EOF) || (lo == EOF)) DIE();
		exec[i] = hi << 8 | lo;
	}
	fclose(fp);
	//-------------------------------------------------------------------
	fp = fopen(DIR GROM, "rb");
	if(!fp) DIE();
	for(i = 0; i < 0x0800; i++) {
		lo = fgetc(fp);
		if(lo == EOF) DIE();
		gmem[i] = lo;
	}
	fclose(fp);
	//-------------------------------------------------------------------
	fp = fopen(fname, "rb");
	if(!fp) DIE();
	for(i = 0; i < 0x1000; i++) {
		hi = fgetc(fp);
		lo = fgetc(fp);
		if((hi == EOF) || (lo == EOF)) break;
		cart[i] = hi << 8 | lo;
	}
	fclose(fp);
	//-------------------------------------------------------------------
}
/****************************************************************************
 *	
 ****************************************************************************/

int
cp1610_read(int addr)
{
	ASSERT((addr >= 0) && (addr <= 0xffff));
	switch(addr & 0xf000) {
	case 0x0000:
		       if(addr < 0x0040) {
			return stic_read(addr - 0x0000);
		} else if(addr < 0x0100) {
			break;
		} else if(addr < 0x01f0) {
			return ram1[addr - 0x0100];
		} else if(addr < 0x0200) {
			return ay38914_read(addr - 0x01f0);
		} else if(addr < 0x0360) {
			return ram2[addr - 0x0200];
		} else {
			break;
		}
	case 0x1000:
		return exec[addr - 0x1000];
	case 0x3000:
		if(addr < 0x3a00) {
			return gmem[addr - 0x3000];
		} else {
			break;
		}
	case 0x5000:
		return cart[addr - 0x5000];
	}
	return 0xffff;
}

void
cp1610_write(int addr, int data)
{
	ASSERT((addr >= 0) && (addr <= 0xffff));
	ASSERT((data >= 0) && (data <= 0xffff));
	switch(addr & 0xf000) {
	case 0x0000:
		       if(addr < 0x0040) {
			stic_write(addr - 0x0000, data);
			return;
		} else if(addr < 0x0100) {
			return;
		} else if(addr < 0x01f0) {
			ram1[addr - 0x0100] = data;
			return;
		} else if(addr < 0x0200) {
			ay38914_write(addr - 0x01f0, data);
			return;
		} else if(addr < 0x0360) {
			ram2[addr - 0x0200] = data;
			return;
		} else {
			return;
		}
	case 0x3000:
		if(addr < 0x3800) {
			return;
		} else if(addr < 0x3a00) {
			gmem[addr - 0x3000] = data;
			return;
		} else {
			return;
		}
	}
}

/****************************************************************************
 *	
 ****************************************************************************/

void
input_update()
{
	ram1[0xfe] = -1;	/* Right */
	ram1[0xff] = ~INPUT;	/* Left  */
}

int
main(int argc, char* argv[])
{
	int t0;
	int t1;
	HDC hDC;
	RECT rc;

	InitUI();
	InitROM(argv[1] ? argv[1] : DIR ROM);
	InitSnd();

	ay38910_reset(&ay38910, AY38914_CLOCK, ay38910_in, ay38910_out);
	stic_reset(ram2, gmem);
	cp1610_reset(0x1000);

	t0 = GetTickCount();
	hDC = GetDC(MainWnd);
	GetClientRect(MainWnd, &rc);
	for(;;) {
		if(!DoMsg()) {
			break;
		}
		input_update();

		cp1610_run(INTV_CLOCK/60);
		cp1610_irq(0x1004);

		stic_update(xbuff);
#ifdef STIC_GRAYSCALE
		stic_reduce(xbuff, xbuff);
#endif /*STIC_GRAYSCALE*/
		StretchDIBits(hDC,
			rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
			0, 0, pBMI->bmiHeader.biWidth, -pBMI->bmiHeader.biHeight,
			xbuff,
			pBMI,
			DIB_RGB_COLORS,
			SRCCOPY);

		for(;;) {
			t1 = GetTickCount();
			if(t1 - t0 >= 1000 / 60) break;
			Sleep(0);
		}
		t0 += 1000 / 60;
	}
	ReleaseDC(MainWnd, hDC);
}
