/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id: helloworld.c,v 1.2 2004/01/08 09:58:58 bagder Exp $
 *
 * Copyright (C) 2002 Björn Stenberg
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#include "plugin.h"
/*#include "test/callced.h"*/

/* LCD required */
#ifdef HAVE_LCD_BITMAP

#define ROM_NAME "/.rockbox/rocktrex/rom.dat"
#define CART_NAME "/.rockbox/rocktrex/Armor Attack (1982).bin"

#define DWORD unsigned long

#define VECTREX_MHZ 1500000
#define VECTREX_REDRAW_RATE 30 /* phosphor decay rate */
/* number of 6809 cycles before a frame redraw */
#define VECTREX_CYCLES_BEFORE_VECTREX_REDRAW (VECTREX_MHZ / VECTREX_REDRAW_RATE)
/* max number of possible vectors that maybe on the screen at one time.
 * one only needs VECTREX_MHZ / VECTREX_REDRAW_RATE but we need to also store
 * deleted vectors in a single table
 */
#define VECTOR_CNT (VECTREX_MHZ / VECTREX_REDRAW_RATE)
#define VECTOR_HASH 65521
#define VECTREX_COLORS 128 /* number of possible colors ... grayscale */
#define ALG_MAX_X 33000
#define ALG_MAX_Y 41000

#define LOCAL_REDRAW_RATE 30
#define LOCAL_TICKS_BEFORE_LOCAL_REDRAW (HZ / LOCAL_REDRAW_RATE)

#define EMU_TIMER_HZ 30 /* in HZ !!! NOT milliseconds */
#define LOCAL_TICKS_BEFORE_EMU_TIMER (HZ / EMU_TIMER_HZ)
#define VECTREX_CYCLES_BEFORE_EMU_TIMER (VECTREX_MHZ / EMU_TIMER_HZ)

typedef struct vector_type {
	long x0, y0; /* start coordinate */
	long x1, y1; /* end coordinate */

	/* color [0, VECTREX_COLORS - 1], if color = VECTREX_COLORS, then this is
	 * an invalid entry and must be ignored.
	 */
	unsigned char color;
} vector_t;

static long next_vectrex_fps_update = 0;
static long vectrex_fps = 0, current_vectrex_fps = 0;
static char fps_display_buffer[4];
static long next_local_fps_update = 0;
static long local_fps = 0, current_local_fps = 0;

static int osint_defaults (void);
static void osint_load_cart (char *cartname);
void osint_emuloop (void);
void osint_render (void);
int process_input (void);

/* for iRiver only at the moment */
/*
#define VK_1      BUTTON_REC
#define VK_2      BUTTON_ON
#define VK_3      BUTTON_SELECT
#define VK_4      BUTTON_MODE
#define VK_QUIT   BUTTON_OFF
#define VK_LEFT   BUTTON_LEFT
#define VK_RIGHT  BUTTON_RIGHT
#define VK_UP     BUTTON_UP
#define VK_DOWN   BUTTON_DOWN
*/

#define VK_1      BUTTON_REC
#define VK_2      BUTTON_ON
#define VK_3      BUTTON_UP
#define VK_4      BUTTON_SELECT
#define VK_QUIT   BUTTON_OFF
#define VK_LEFT   BUTTON_LEFT
#define VK_RIGHT  BUTTON_RIGHT
#define VK_UP     BUTTON_MODE
#define VK_DOWN   BUTTON_DOWN

/* global api struct pointer */
static struct plugin_api* rb;

/* plugin entry point */
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
    /* variable declarations */
    
    /* compatibility check */
    TEST_PLUGIN_API(api);
    /* if parameters are not used */
    (void)parameter;
    /* if the plugin api is used, must be copied */
    rb = api;

    /* splash screen (what's the second param?) */
    /* rb->splash(HZ*2, true, "RockTrex"); */
	/*int a = 1, b = 3;
	printf("Entre %d et %d, le plus grand nombre est %d\n", a, b, call_ced_max(a, b));*/

    rb->lcd_clear_display();
	rb->lcd_setfont(FONT_SYSFIXED);
    
	osint_defaults ();
#ifdef CART_NAME
	osint_load_cart(CART_NAME);
#endif
	osint_emuloop ();
    
	/* when using button_status in the main loop, we have to make sure the input buffers are
	   empty before leaving */
	while (rb->button_get(false) != BUTTON_NONE)  ;
	rb->button_clear_queue();
	
    /* don't know the other values, have to check include files */
	return PLUGIN_OK;
}



/**************************************
** CONTENT OF THE E6809.C FILE
**************************************/

/* code assumptions:
 *  - it is assumed that an 'int' is at least 16 bits long.
 *  - a 16-bit register has valid bits only in the lower 16 bits and an
 *    8-bit register has valid bits only in the lower 8 bits. the upper
 *    may contain garbage!
 *  - all reading functions are assumed to return the requested data in
 *    the lower bits with the unused upper bits all set to zero.
 */

#define einline __inline

enum {
	FLAG_E		= 0x80,
	FLAG_F		= 0x40,
	FLAG_H		= 0x20,
	FLAG_I		= 0x10,
	FLAG_N		= 0x08,
	FLAG_Z		= 0x04,
	FLAG_V		= 0x02,
	FLAG_C		= 0x01,
	IRQ_NORMAL	= 0,
	IRQ_SYNC	= 1,
	IRQ_CWAI	= 2
};

/* index registers */
static unsigned reg_x;
static unsigned reg_y;

/* user stack pointer */
static unsigned reg_u;

/* hardware stack pointer */
static unsigned reg_s;

/* program counter */
static unsigned reg_pc;

/* accumulators */
static unsigned reg_a;
static unsigned reg_b;

/* direct page register */
static unsigned reg_dp;

/* condition codes */
static unsigned reg_cc;

/* flag to see if interrupts should be handled (sync/cwai). */
static unsigned irq_status;

static unsigned *rptr_xyus[4] = {
	&reg_x,
	&reg_y,
	&reg_u,
	&reg_s
};

/* user defined read and write functions */
unsigned char (*e6809_read8) (unsigned address);
void (*e6809_write8) (unsigned address, unsigned char data);

/* obtain a particular condition code. returns 0 or 1. */
static einline unsigned get_cc (unsigned flag)
{
	return (reg_cc / flag) & 1;
}

/* set a particular condition code to either 0 or 1.
 * value parameter must be either 0 or 1.
 */
static einline void set_cc (unsigned flag, unsigned value)
{
	reg_cc &= ~flag;
	reg_cc |= value * flag;
}

/* test carry */
static einline unsigned test_c (unsigned i0, unsigned i1,
								unsigned r, unsigned sub)
{
	unsigned flag;

	flag  = (i0 | i1) & ~r; /* one of the inputs is 1 and output is 0 */
	flag |= (i0 & i1);      /* both inputs are 1 */
	flag  = (flag >> 7) & 1;
	flag ^= sub; /* on a sub, carry is opposite the carry of an add */

	return flag;
}

/* test negative */
static einline unsigned test_n (unsigned r)
{
	return (r >> 7) & 1;
}

/* test for zero in lower 8 bits */
static einline unsigned test_z8 (unsigned r)
{
	unsigned flag;

	flag = ~r;
	flag = (flag >> 4) & (flag & 0xf);
	flag = (flag >> 2) & (flag & 0x3);
	flag = (flag >> 1) & (flag & 0x1);

	return flag;
}

/* test for zero in lower 16 bits */
static einline unsigned test_z16 (unsigned r)
{
	unsigned flag;

	flag = ~r;
	flag = (flag >> 8) & (flag & 0xff);
	flag = (flag >> 4) & (flag & 0xf);
	flag = (flag >> 2) & (flag & 0x3);
	flag = (flag >> 1) & (flag & 0x1);

	return flag;
}

/* overflow is set whenever the sign bits of the inputs are the same
 * but the sign bit of the result is not same as the sign bits of the
 * inputs.
 */
static einline unsigned test_v (unsigned i0, unsigned i1, unsigned r)
{
	unsigned flag;

	flag  = ~(i0 ^ i1); /* input sign bits are the same */
	flag &=  (i0 ^ r);  /* input sign and output sign not same */
	flag  = (flag >> 7) & 1;

	return flag;
}

static einline unsigned get_reg_d (void)
{
	return (reg_a << 8) | (reg_b & 0xff);
}

static einline void set_reg_d (unsigned value)
{
	reg_a = value >> 8;
	reg_b = value;
}

/* read a byte ... the returned value has the lower 8-bits set to the byte
 * while the upper bits are all zero.
 */
unsigned char read8 (unsigned address);
void write8 (unsigned address, unsigned char data);

/*static einline unsigned read8 (unsigned address)
{
	return (*e6809_read8) (address & 0xffff);
}*/

/* write a byte ... only the lower 8-bits of the unsigned data
 * is written. the upper bits are ignored.
 */

/*static einline void write8 (unsigned address, unsigned data)
{
	(*e6809_write8) (address & 0xffff, (unsigned char) data);
}*/

static einline unsigned read16 (unsigned address)
{
	unsigned datahi, datalo;

	datahi = read8 (address);
	datalo = read8 (address + 1);

	return (datahi << 8) | datalo;
}

static einline void write16 (unsigned address, unsigned data)
{
	write8 (address, data >> 8);
	write8 (address + 1, data);
}

static einline void push8 (unsigned *sp, unsigned data)
{
	(*sp)--;
	write8 (*sp, data);
}

static einline unsigned pull8 (unsigned *sp)
{
	unsigned data;

	data = read8 (*sp);
	(*sp)++;

	return data;
}

static einline void push16 (unsigned *sp, unsigned data)
{
	push8 (sp, data);
	push8 (sp, data >> 8);
}

static einline unsigned pull16 (unsigned *sp)
{
	unsigned datahi, datalo;

	datahi = pull8 (sp);
	datalo = pull8 (sp);

	return (datahi << 8) | datalo;
}

/* read a byte from the address pointed to by the pc */
static einline unsigned pc_read8 (void)
{
	unsigned data;

	data = read8 (reg_pc);
	reg_pc++;

	return data;
}

/* read a word from the address pointed to by the pc */
static einline unsigned pc_read16 (void)
{
	unsigned data;

	data = read16 (reg_pc);
	reg_pc += 2;

	return data;
}

/* sign extend an 8-bit quantity into a 16-bit quantity */
static einline unsigned sign_extend (unsigned data)
{
	return (~(data & 0x80) + 1) | (data & 0xff);
}

/* direct addressing, upper byte of the address comes from
 * the direct page register, and the lower byte comes from the
 * instruction itself.
 */
static einline unsigned ea_direct (void)
{
	return (reg_dp << 8) | pc_read8 ();
}

/* extended addressing, address is obtained from 2 bytes following
 * the instruction.
 */
static einline unsigned ea_extended (void)
{
	return pc_read16 ();
}

/* indexed addressing */
static einline unsigned ea_indexed (unsigned *cycles)
{
	unsigned r, op, ea;

	/* post byte */

	op = pc_read8 ();

	r = (op >> 5) & 3;

	switch (op) {
	case 0x00: case 0x01: case 0x02: case 0x03:
	case 0x04: case 0x05: case 0x06: case 0x07:
	case 0x08: case 0x09: case 0x0a: case 0x0b:
	case 0x0c: case 0x0d: case 0x0e: case 0x0f:
	case 0x20: case 0x21: case 0x22: case 0x23:
	case 0x24: case 0x25: case 0x26: case 0x27:
	case 0x28: case 0x29: case 0x2a: case 0x2b:
	case 0x2c: case 0x2d: case 0x2e: case 0x2f:
	case 0x40: case 0x41: case 0x42: case 0x43:
	case 0x44: case 0x45: case 0x46: case 0x47:
	case 0x48: case 0x49: case 0x4a: case 0x4b:
	case 0x4c: case 0x4d: case 0x4e: case 0x4f:
	case 0x60: case 0x61: case 0x62: case 0x63:
	case 0x64: case 0x65: case 0x66: case 0x67:
	case 0x68: case 0x69: case 0x6a: case 0x6b:
	case 0x6c: case 0x6d: case 0x6e: case 0x6f:
		/* R, +[0, 15] */

		ea = *rptr_xyus[r] + (op & 0xf);
		(*cycles)++;
		break;
	case 0x10: case 0x11: case 0x12: case 0x13:
	case 0x14: case 0x15: case 0x16: case 0x17:
	case 0x18: case 0x19: case 0x1a: case 0x1b:
	case 0x1c: case 0x1d: case 0x1e: case 0x1f:
	case 0x30: case 0x31: case 0x32: case 0x33:
	case 0x34: case 0x35: case 0x36: case 0x37:
	case 0x38: case 0x39: case 0x3a: case 0x3b:
	case 0x3c: case 0x3d: case 0x3e: case 0x3f:
	case 0x50: case 0x51: case 0x52: case 0x53:
	case 0x54: case 0x55: case 0x56: case 0x57:
	case 0x58: case 0x59: case 0x5a: case 0x5b:
	case 0x5c: case 0x5d: case 0x5e: case 0x5f:
	case 0x70: case 0x71: case 0x72: case 0x73:
	case 0x74: case 0x75: case 0x76: case 0x77:
	case 0x78: case 0x79: case 0x7a: case 0x7b:
	case 0x7c: case 0x7d: case 0x7e: case 0x7f:
		/* R, +[-16, -1] */

		ea = *rptr_xyus[r] + (op & 0xf) - 0x10;
		(*cycles)++;
		break;
	case 0x80: case 0x81:
	case 0xa0: case 0xa1:
	case 0xc0: case 0xc1:
	case 0xe0: case 0xe1:
		/* ,R+ / ,R++ */

		ea = *rptr_xyus[r];
		*rptr_xyus[r] += 1 + (op & 1);
		*cycles += 2 + (op & 1);
		break;
	case 0x90: case 0x91:
	case 0xb0: case 0xb1:
	case 0xd0: case 0xd1:
	case 0xf0: case 0xf1:
		/* [,R+] ??? / [,R++] */

		ea = read16 (*rptr_xyus[r]);
		*rptr_xyus[r] += 1 + (op & 1);
		*cycles += 5 + (op & 1);
		break;
	case 0x82: case 0x83:
	case 0xa2: case 0xa3:
	case 0xc2: case 0xc3:
	case 0xe2: case 0xe3:

		/* ,-R / ,--R */

		*rptr_xyus[r] -= 1 + (op & 1);
		ea = *rptr_xyus[r];
		*cycles += 2 + (op & 1);
		break;
	case 0x92: case 0x93:
	case 0xb2: case 0xb3:
	case 0xd2: case 0xd3:
	case 0xf2: case 0xf3:
		/* [,-R] ??? / [,--R] */

		*rptr_xyus[r] -= 1 + (op & 1);
		ea = read16 (*rptr_xyus[r]);
		*cycles += 5 + (op & 1);
		break;
	case 0x84: case 0xa4:
	case 0xc4: case 0xe4:
		/* ,R */

		ea = *rptr_xyus[r];
		break;
	case 0x94: case 0xb4:
	case 0xd4: case 0xf4:
		/* [,R] */

		ea = read16 (*rptr_xyus[r]);
		*cycles += 3;
		break;
	case 0x85: case 0xa5:
	case 0xc5: case 0xe5:
		/* B,R */

		ea = *rptr_xyus[r] + sign_extend (reg_b);
		*cycles += 1;
		break;
	case 0x95: case 0xb5:
	case 0xd5: case 0xf5:
		/* [B,R] */

		ea = read16 (*rptr_xyus[r] + sign_extend (reg_b));
		*cycles += 4;
		break;
	case 0x86: case 0xa6:
	case 0xc6: case 0xe6:
		/* A,R */

		ea = *rptr_xyus[r] + sign_extend (reg_a);
		*cycles += 1;
		break;
	case 0x96: case 0xb6:
	case 0xd6: case 0xf6:
		/* [A,R] */

		ea = read16 (*rptr_xyus[r] + sign_extend (reg_a));
		*cycles += 4;
		break;
	case 0x88: case 0xa8:
	case 0xc8: case 0xe8:
		/* byte,R */

		ea = *rptr_xyus[r] + sign_extend (pc_read8 ());
		*cycles += 1;
		break;
	case 0x98: case 0xb8:
	case 0xd8: case 0xf8:
		/* [byte,R] */

		ea = read16 (*rptr_xyus[r] + sign_extend (pc_read8 ()));
		*cycles += 4;
		break;
	case 0x89: case 0xa9:
	case 0xc9: case 0xe9:
		/* word,R */

		ea = *rptr_xyus[r] + pc_read16 ();
		*cycles += 4;
		break;
	case 0x99: case 0xb9:
	case 0xd9: case 0xf9:
		/* [word,R] */

		ea = read16 (*rptr_xyus[r] + pc_read16 ());
		*cycles += 7;
		break;
	case 0x8b: case 0xab:
	case 0xcb: case 0xeb:
		/* D,R */

		ea = *rptr_xyus[r] + get_reg_d ();
		*cycles += 4;
		break;
	case 0x9b: case 0xbb:
	case 0xdb: case 0xfb:
		/* [D,R] */

		ea = read16 (*rptr_xyus[r] + get_reg_d ());
		*cycles += 7;
		break;
	case 0x8c: case 0xac:
	case 0xcc: case 0xec:
		/* byte, PC */

		r = sign_extend (pc_read8 ());
		ea = reg_pc + r;
		*cycles += 1;
		break;
	case 0x9c: case 0xbc:
	case 0xdc: case 0xfc:
		/* [byte, PC] */

		r = sign_extend (pc_read8 ());
		ea = read16 (reg_pc + r);
		*cycles += 4;
		break;
	case 0x8d: case 0xad:
	case 0xcd: case 0xed:
		/* word, PC */

		r = pc_read16 ();
		ea = reg_pc + r;
		*cycles += 5;
		break;
	case 0x9d: case 0xbd:
	case 0xdd: case 0xfd:
		/* [word, PC] */

		r = pc_read16 ();
		ea = read16 (reg_pc + r);
		*cycles += 8;
		break;
	case 0x9f:
		/* [address] */

		ea = read16 (pc_read16 ());
		*cycles += 5;
		break;
	default:
		/*printf ("undefined post-byte\n");*/
		break;
	}

	return ea;
}

/* instruction: neg
 * essentially (0 - data).
 */
einline unsigned inst_neg (unsigned data)
{
	unsigned i0, i1, r;

	i0 = 0;
	i1 = ~data;
	r = i0 + i1 + 1;

	set_cc (FLAG_H, test_c (i0 << 4, i1 << 4, r << 4, 0));
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));
	set_cc (FLAG_C, test_c (i0, i1, r, 1));

	return r;
}

/* instruction: com */
einline unsigned inst_com (unsigned data)
{
	unsigned r;

	r = ~data;
	
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, 0);
	set_cc (FLAG_C, 1);

	return r;
}

/* instruction: lsr
 * cannot be faked as an add or substract.
 */
einline unsigned inst_lsr (unsigned data)
{
	unsigned r;

	r = (data >> 1) & 0x7f;
	
	set_cc (FLAG_N, 0);
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_C, data & 1);

	return r;
}

/* instruction: ror
 * cannot be faked as an add or substract.
 */
einline unsigned inst_ror (unsigned data)
{
	unsigned r, c;

	c = get_cc (FLAG_C);
	r = ((data >> 1) & 0x7f) | (c << 7);
	
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_C, data & 1);

	return r;
}

/* instruction: asr
 * cannot be faked as an add or substract.
 */
einline unsigned inst_asr (unsigned data)
{
	unsigned r;

	r = ((data >> 1) & 0x7f) | (data & 0x80);
	
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_C, data & 1);

	return r;
}

/* instruction: asl
 * essentially (data + data). simple addition.
 */
einline unsigned inst_asl (unsigned data)
{
	unsigned i0, i1, r;

	i0 = data;
	i1 = data;
	r = i0 + i1;
	
	set_cc (FLAG_H, test_c (i0 << 4, i1 << 4, r << 4, 0));
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));
	set_cc (FLAG_C, test_c (i0, i1, r, 0));

	return r;
}

/* instruction: rol
 * essentially (data + data + carry). addition with carry.
 */
einline unsigned inst_rol (unsigned data)
{
	unsigned i0, i1, c, r;

	i0 = data;
	i1 = data;
	c = get_cc (FLAG_C);
	r = i0 + i1 + c;
	
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));
	set_cc (FLAG_C, test_c (i0, i1, r, 0));

	return r;
}

/* instruction: dec
 * essentially (data - 1).
 */
einline unsigned inst_dec (unsigned data)
{
	unsigned i0, i1, r;

	i0 = data;
	i1 = 0xff;
	r = i0 + i1;
	
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));

	return r;
}

/* instruction: inc
 * essentially (data + 1).
 */
einline unsigned inst_inc (unsigned data)
{
	unsigned i0, i1, r;

	i0 = data;
	i1 = 1;
	r = i0 + i1;
	
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));

	return r;
}

/* instruction: tst */
einline void inst_tst8 (unsigned data)
{
	set_cc (FLAG_N, test_n (data));
	set_cc (FLAG_Z, test_z8 (data));
	set_cc (FLAG_V, 0);
}

einline void inst_tst16 (unsigned data)
{
	set_cc (FLAG_N, test_n (data >> 8));
	set_cc (FLAG_Z, test_z16 (data));
	set_cc (FLAG_V, 0);
}

/* instruction: clr */
einline void inst_clr (void)
{
	set_cc (FLAG_N, 0);
	set_cc (FLAG_Z, 1);
	set_cc (FLAG_V, 0);
	set_cc (FLAG_C, 0);
}

/* instruction: suba/subb */
einline unsigned inst_sub8 (unsigned data0, unsigned data1)
{
	unsigned i0, i1, r;

	i0 = data0;
	i1 = ~data1;
	r = i0 + i1 + 1;
	
	set_cc (FLAG_H, test_c (i0 << 4, i1 << 4, r << 4, 0));
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));
	set_cc (FLAG_C, test_c (i0, i1, r, 1));

	return r;
}

/* instruction: sbca/sbcb/cmpa/cmpb.
 * only 8-bit version, 16-bit version not needed.
 */
einline unsigned inst_sbc (unsigned data0, unsigned data1)
{
	unsigned i0, i1, c, r;

	i0 = data0;
	i1 = ~data1;
	c = 1 - get_cc (FLAG_C);
	r = i0 + i1 + c;

	set_cc (FLAG_H, test_c (i0 << 4, i1 << 4, r << 4, 0));
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));
	set_cc (FLAG_C, test_c (i0, i1, r, 1));

	return r;
}

/* instruction: anda/andb/bita/bitb.
 * only 8-bit version, 16-bit version not needed.
 */
einline unsigned inst_and (unsigned data0, unsigned data1)
{
	unsigned r;

	r = data0 & data1;

	inst_tst8 (r);

	return r;
}

/* instruction: eora/eorb.
 * only 8-bit version, 16-bit version not needed.
 */
einline unsigned inst_eor (unsigned data0, unsigned data1)
{
	unsigned r;

	r = data0 ^ data1;

	inst_tst8 (r);

	return r;
}

/* instruction: adca/adcb
 * only 8-bit version, 16-bit version not needed.
 */
einline unsigned inst_adc (unsigned data0, unsigned data1)
{
	unsigned i0, i1, c, r;

	i0 = data0;
	i1 = data1;
	c = get_cc (FLAG_C);
	r = i0 + i1 + c;

	set_cc (FLAG_H, test_c (i0 << 4, i1 << 4, r << 4, 0));
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));
	set_cc (FLAG_C, test_c (i0, i1, r, 0));

	return r;
}

/* instruction: ora/orb.
 * only 8-bit version, 16-bit version not needed.
 */
einline unsigned inst_or (unsigned data0, unsigned data1)
{
	unsigned r;

	r = data0 | data1;

	inst_tst8 (r);

	return r;
}

/* instruction: adda/addb */
einline unsigned inst_add8 (unsigned data0, unsigned data1)
{
	unsigned i0, i1, r;

	i0 = data0;
	i1 = data1;
	r = i0 + i1;

	set_cc (FLAG_H, test_c (i0 << 4, i1 << 4, r << 4, 0));
	set_cc (FLAG_N, test_n (r));
	set_cc (FLAG_Z, test_z8 (r));
	set_cc (FLAG_V, test_v (i0, i1, r));
	set_cc (FLAG_C, test_c (i0, i1, r, 0));

	return r;
}

/* instruction: addd */
einline unsigned inst_add16 (unsigned data0, unsigned data1)
{
	unsigned i0, i1, r;

	i0 = data0;
	i1 = data1;
	r = i0 + i1;

	set_cc (FLAG_N, test_n (r >> 8));
	set_cc (FLAG_Z, test_z16 (r));
	set_cc (FLAG_V, test_v (i0 >> 8, i1 >> 8, r >> 8));
	set_cc (FLAG_C, test_c (i0 >> 8, i1 >> 8, r >> 8, 0));

	return r;
}

/* instruction: subd */
einline unsigned inst_sub16 (unsigned data0, unsigned data1)
{
	unsigned i0, i1, r;

	i0 = data0;
	i1 = ~data1;
	r = i0 + i1 + 1;

	set_cc (FLAG_N, test_n (r >> 8));
	set_cc (FLAG_Z, test_z16 (r));
	set_cc (FLAG_V, test_v (i0 >> 8, i1 >> 8, r >> 8));
	set_cc (FLAG_C, test_c (i0 >> 8, i1 >> 8, r >> 8, 1));

	return r;
}

/* instruction: 8-bit offset branch */
einline void inst_bra8 (unsigned test, unsigned op, unsigned *cycles)
{
	unsigned offset, mask;

	offset = pc_read8 ();

	/* trying to avoid an if statement */

	mask = (test ^ (op & 1)) - 1; /* 0xffff when taken, 0 when not taken */
	reg_pc += sign_extend (offset) & mask;

	*cycles += 3;
}

/* instruction: 16-bit offset branch */
einline void inst_bra16 (unsigned test, unsigned op, unsigned *cycles)
{
	unsigned offset, mask;

	offset = pc_read16 ();

	/* trying to avoid an if statement */

	mask = (test ^ (op & 1)) - 1; /* 0xffff when taken, 0 when not taken */
	reg_pc += offset & mask;

	*cycles += 5 - mask;
}

/* instruction: pshs/pshu */
einline void inst_psh (unsigned op, unsigned *sp,
					   unsigned data, unsigned *cycles)
{
	if (op & 0x80) {
		push16 (sp, reg_pc);
		*cycles += 2;
	}

	if (op & 0x40) {
		/* either s or u */
		push16 (sp, data);
		*cycles += 2;
	}

	if (op & 0x20) {
		push16 (sp, reg_y);
		*cycles += 2;
	}

	if (op & 0x10) {
		push16 (sp, reg_x);
		*cycles += 2;
	}

	if (op & 0x08) {
		push8 (sp, reg_dp);
		*cycles += 1;
	}

	if (op & 0x04) {
		push8 (sp, reg_b);
		*cycles += 1;
	}

	if (op & 0x02) {
		push8 (sp, reg_a);
		*cycles += 1;
	}

	if (op & 0x01) {
		push8 (sp, reg_cc);
		*cycles += 1;
	}
}

/* instruction: puls/pulu */
einline void inst_pul (unsigned op, unsigned *sp, unsigned *osp,
					   unsigned *cycles)
{
	if (op & 0x01) {
		reg_cc = pull8 (sp);
		*cycles += 1;
	}

	if (op & 0x02) {
		reg_a = pull8 (sp);
		*cycles += 1;
	}

	if (op & 0x04) {
		reg_b = pull8 (sp);
		*cycles += 1;
	}

	if (op & 0x08) {
		reg_dp = pull8 (sp);
		*cycles += 1;
	}

	if (op & 0x10) {
		reg_x = pull16 (sp);
		*cycles += 2;
	}

	if (op & 0x20) {
		reg_y = pull16 (sp);
		*cycles += 2;
	}

	if (op & 0x40) {
		/* either s or u */
		*osp = pull16 (sp);
		*cycles += 2;
	}

	if (op & 0x80) {
		reg_pc = pull16 (sp);
		*cycles += 2;
	}
}

einline unsigned exgtfr_read (unsigned reg)
{
	unsigned data;

	switch (reg) {
	case 0x0:
		data = get_reg_d ();
		break;
	case 0x1:
		data = reg_x;
		break;
	case 0x2:
		data = reg_y;
		break;
	case 0x3:
		data = reg_u;
		break;
	case 0x4:
		data = reg_s;
		break;
	case 0x5:
		data = reg_pc;
		break;
	case 0x8:
		data = 0xff00 | reg_a;
		break;
	case 0x9:
		data = 0xff00 | reg_b;
		break;
	case 0xa:
		data = 0xff00 | reg_cc;
		break;
	case 0xb:
		data = 0xff00 | reg_dp;
		break;
	default:
		data = 0xffff;
		/*printf ("illegal exgtfr reg %.1x\n", reg);*/
		break;
	}

	return data;
}

einline void exgtfr_write (unsigned reg, unsigned data)
{
	switch (reg) {
	case 0x0:
		set_reg_d (data);
		break;
	case 0x1:
		reg_x = data;
		break;
	case 0x2:
		reg_y = data;
		break;
	case 0x3:
		reg_u = data;
		break;
	case 0x4:
		reg_s = data;
		break;
	case 0x5:
		reg_pc = data;
		break;
	case 0x8:
		reg_a = data;
		break;
	case 0x9:
		reg_b = data;
		break;
	case 0xa:
		reg_cc = data;
		break;
	case 0xb:
		reg_dp = data;
		break;
	default:
		/*printf ("illegal exgtfr reg %.1x\n", reg);*/
		break;
	}
}

/* instruction: exg */
einline void inst_exg (void)
{
	unsigned op, tmp;

	op = pc_read8 ();

	tmp = exgtfr_read (op & 0xf);
	exgtfr_write (op & 0xf, exgtfr_read (op >> 4));
	exgtfr_write (op >> 4, tmp);
}

/* instruction: tfr */
einline void inst_tfr (void)
{
	unsigned op;

	op = pc_read8 ();

	exgtfr_write (op & 0xf, exgtfr_read (op >> 4));
}

/* reset the 6809 */
void e6809_reset (void)
{
	reg_x = 0;
	reg_y = 0;
	reg_u = 0;
	reg_s = 0;

	reg_a = 0;
	reg_b = 0;

	reg_dp = 0;

	reg_cc = FLAG_I | FLAG_F;
	irq_status = IRQ_NORMAL;

	reg_pc = read16 (0xfffe);
}

/* execute a single instruction or handle interrupts and return */
unsigned e6809_sstep (unsigned irq_i, unsigned irq_f)
{
	unsigned op;
	unsigned cycles = 0;
	unsigned ea, i0, i1, r;

	if (irq_f) {
		if (get_cc (FLAG_F) == 0) {
			if (irq_status != IRQ_CWAI) {
				set_cc (FLAG_E, 0);
				inst_psh (0x81, &reg_s, reg_u, &cycles);
			}

			set_cc (FLAG_I, 1);
			set_cc (FLAG_F, 1);

			reg_pc = read16 (0xfff6);
			irq_status = IRQ_NORMAL;
			cycles += 7;
		} else {
			if (irq_status == IRQ_SYNC) {
				irq_status = IRQ_NORMAL;
			}
		}
	}
	
	if (irq_i) {
		if (get_cc (FLAG_I) == 0) {
			if (irq_status != IRQ_CWAI) {
				set_cc (FLAG_E, 1);
				inst_psh (0xff, &reg_s, reg_u, &cycles);
			}

			set_cc (FLAG_I, 1);

			reg_pc = read16 (0xfff8);
			irq_status = IRQ_NORMAL;
			cycles += 7;
		} else {
			if (irq_status == IRQ_SYNC) {
				irq_status = IRQ_NORMAL;
			}
		}
	}

	if (irq_status != IRQ_NORMAL) {
		return cycles + 1;
	}

	op = pc_read8 ();

	switch (op) {
	/* page 0 instructions */

	/* neg, nega, negb */
	case 0x00:
		ea = ea_direct ();
		r = inst_neg (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x40:
		reg_a = inst_neg (reg_a);
		cycles += 2;
		break;
		
	case 0x50:
		reg_b = inst_neg (reg_b);
		cycles += 2;
		break;
		
	case 0x60:
		ea = ea_indexed (&cycles);
		r = inst_neg (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x70:
		ea = ea_extended ();
		r = inst_neg (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* com, coma, comb */
	case 0x03:
		ea = ea_direct ();
		r = inst_com (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x43:
		reg_a = inst_com (reg_a);
		cycles += 2;
		break;
		
	case 0x53:
		reg_b = inst_com (reg_b);
		cycles += 2;
		break;
		
	case 0x63:
		ea = ea_indexed (&cycles);
		r = inst_com (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x73:
		ea = ea_extended ();
		r = inst_com (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* lsr, lsra, lsrb */
	case 0x04:
		ea = ea_direct ();
		r = inst_lsr (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x44:
		reg_a = inst_lsr (reg_a);
		cycles += 2;
		break;
		
	case 0x54:
		reg_b = inst_lsr (reg_b);
		cycles += 2;
		break;
		
	case 0x64:
		ea = ea_indexed (&cycles);
		r = inst_lsr (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x74:
		ea = ea_extended ();
		r = inst_lsr (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* ror, rora, rorb */
	case 0x06:
		ea = ea_direct ();
		r = inst_ror (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x46:
		reg_a = inst_ror (reg_a);
		cycles += 2;
		break;
		
	case 0x56:
		reg_b = inst_ror (reg_b);
		cycles += 2;
		break;
		
	case 0x66:
		ea = ea_indexed (&cycles);
		r = inst_ror (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x76:
		ea = ea_extended ();
		r = inst_ror (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* asr, asra, asrb */
	case 0x07:
		ea = ea_direct ();
		r = inst_asr (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x47:
		reg_a = inst_asr (reg_a);
		cycles += 2;
		break;
		
	case 0x57:
		reg_b = inst_asr (reg_b);
		cycles += 2;
		break;
		
	case 0x67:
		ea = ea_indexed (&cycles);
		r = inst_asr (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x77:
		ea = ea_extended ();
		r = inst_asr (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* asl, asla, aslb */
	case 0x08:
		ea = ea_direct ();
		r = inst_asl (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x48:
		reg_a = inst_asl (reg_a);
		cycles += 2;
		break;
		
	case 0x58:
		reg_b = inst_asl (reg_b);
		cycles += 2;
		break;
		
	case 0x68:
		ea = ea_indexed (&cycles);
		r = inst_asl (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x78:
		ea = ea_extended ();
		r = inst_asl (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* rol, rola, rolb */
	case 0x09:
		ea = ea_direct ();
		r = inst_rol (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x49:
		reg_a = inst_rol (reg_a);
		cycles += 2;
		break;
		
	case 0x59:
		reg_b = inst_rol (reg_b);
		cycles += 2;
		break;
		
	case 0x69:
		ea = ea_indexed (&cycles);
		r = inst_rol (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x79:
		ea = ea_extended ();
		r = inst_rol (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* dec, deca, decb */
	case 0x0a:
		ea = ea_direct ();
		r = inst_dec (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x4a:
		reg_a = inst_dec (reg_a);
		cycles += 2;
		break;
		
	case 0x5a:
		reg_b = inst_dec (reg_b);
		cycles += 2;
		break;
		
	case 0x6a:
		ea = ea_indexed (&cycles);
		r = inst_dec (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x7a:
		ea = ea_extended ();
		r = inst_dec (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* inc, inca, incb */
	case 0x0c:
		ea = ea_direct ();
		r = inst_inc (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x4c:
		reg_a = inst_inc (reg_a);
		cycles += 2;
		break;
		
	case 0x5c:
		reg_b = inst_inc (reg_b);
		cycles += 2;
		break;
		
	case 0x6c:
		ea = ea_indexed (&cycles);
		r = inst_inc (read8 (ea));
		write8 (ea, r);
		cycles += 6;
		break;
		
	case 0x7c:
		ea = ea_extended ();
		r = inst_inc (read8 (ea));
		write8 (ea, r);
		cycles += 7;
		break;
		
	/* tst, tsta, tstb */
	case 0x0d:
		ea = ea_direct ();
		inst_tst8 (read8 (ea));
		cycles += 6;
		break;
		
	case 0x4d:
		inst_tst8 (reg_a);
		cycles += 2;
		break;
		
	case 0x5d:
		inst_tst8 (reg_b);
		cycles += 2;
		break;
		
	case 0x6d:
		ea = ea_indexed (&cycles);
		inst_tst8 (read8 (ea));
		cycles += 6;
		break;
		
	case 0x7d:
		ea = ea_extended ();
		inst_tst8 (read8 (ea));
		cycles += 7;
		break;
		
	/* jmp */
	case 0x0e:
		reg_pc = ea_direct ();
		cycles += 3;
		break;
		
	case 0x6e:
		reg_pc = ea_indexed (&cycles);
		cycles += 3;
		break;
		
	case 0x7e:
		reg_pc = ea_extended ();
		cycles += 4;
		break;
		
	/* clr */
	case 0x0f:
		ea = ea_direct ();
		inst_clr ();
		write8 (ea, 0);
		cycles += 6;
		break;
		
	case 0x4f:
		inst_clr ();
		reg_a = 0;
		cycles += 2;
		break;
		
	case 0x5f:
		inst_clr ();
		reg_b = 0;
		cycles += 2;
		break;
		
	case 0x6f:
		ea = ea_indexed (&cycles);
		inst_clr ();
		write8 (ea, 0);
		cycles += 6;
		break;
		
	case 0x7f:
		ea = ea_extended ();
		inst_clr ();
		write8 (ea, 0);
		cycles += 7;
		break;
		
	/* suba */
	case 0x80:
		reg_a = inst_sub8 (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x90:
		ea = ea_direct ();
		reg_a = inst_sub8 (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xa0:
		ea = ea_indexed (&cycles);
		reg_a = inst_sub8 (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xb0:
		ea = ea_extended ();
		reg_a = inst_sub8 (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* subb */
	case 0xc0:
		reg_b = inst_sub8 (reg_b, pc_read8 ());
		cycles += 2;
		break;
		
	case 0xd0:
		ea = ea_direct ();
		reg_b = inst_sub8 (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xe0:
		ea = ea_indexed (&cycles);
		reg_b = inst_sub8 (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xf0:
		ea = ea_extended ();
		reg_b = inst_sub8 (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* cmpa */
	case 0x81:
		inst_sub8 (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x91:
		ea = ea_direct ();
		inst_sub8 (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xa1:
		ea = ea_indexed (&cycles);
		inst_sub8 (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xb1:
		ea = ea_extended ();
		inst_sub8 (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* cmpb */
	case 0xc1:
		inst_sub8 (reg_b, pc_read8 ());
		cycles += 2;
		break;
		
	case 0xd1:
		ea = ea_direct ();
		inst_sub8 (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xe1:
		ea = ea_indexed (&cycles);
		inst_sub8 (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xf1:
		ea = ea_extended ();
		inst_sub8 (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* sbca */
	case 0x82:
		reg_a = inst_sbc (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x92:
		ea = ea_direct ();
		reg_a = inst_sbc (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xa2:
		ea = ea_indexed (&cycles);
		reg_a = inst_sbc (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xb2:
		ea = ea_extended ();
		reg_a = inst_sbc (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* sbcb */
	case 0xc2:
		reg_b = inst_sbc (reg_b, pc_read8 ());
		cycles += 2;
		break;
		
	case 0xd2:
		ea = ea_direct ();
		reg_b = inst_sbc (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xe2:
		ea = ea_indexed (&cycles);
		reg_b = inst_sbc (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xf2:
		ea = ea_extended ();
		reg_b = inst_sbc (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* anda */
	case 0x84:
		reg_a = inst_and (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x94:
		ea = ea_direct ();
		reg_a = inst_and (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xa4:
		ea = ea_indexed (&cycles);
		reg_a = inst_and (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xb4:
		ea = ea_extended ();
		reg_a = inst_and (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* andb */
	case 0xc4:
		reg_b = inst_and (reg_b, pc_read8 ());
		cycles += 2;
		break;
		
	case 0xd4:
		ea = ea_direct ();
		reg_b = inst_and (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xe4:
		ea = ea_indexed (&cycles);
		reg_b = inst_and (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xf4:
		ea = ea_extended ();
		reg_b = inst_and (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* bita */
	case 0x85:
		inst_and (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x95:
		ea = ea_direct ();
		inst_and (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xa5:
		ea = ea_indexed (&cycles);
		inst_and (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xb5:
		ea = ea_extended ();
		inst_and (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* bitb */
	case 0xc5:
		inst_and (reg_b, pc_read8 ());
		cycles += 2;
		break;
		
	case 0xd5:
		ea = ea_direct ();
		inst_and (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xe5:
		ea = ea_indexed (&cycles);
		inst_and (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xf5:
		ea = ea_extended ();
		inst_and (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* lda */
	case 0x86:
		reg_a = pc_read8 ();
		inst_tst8 (reg_a);
		cycles += 2;
		break;
		
	case 0x96:
		ea = ea_direct ();
		reg_a = read8 (ea);
		inst_tst8 (reg_a);
		cycles += 4;
		break;
		
	case 0xa6:
		ea = ea_indexed (&cycles);
		reg_a = read8 (ea);
		inst_tst8 (reg_a);
		cycles += 4;
		break;
		
	case 0xb6:
		ea = ea_extended ();
		reg_a = read8 (ea);
		inst_tst8 (reg_a);
		cycles += 5;
		break;
		
	/* ldb */
	case 0xc6:
		reg_b = pc_read8 ();
		inst_tst8 (reg_b);
		cycles += 2;
		break;
		
	case 0xd6:
		ea = ea_direct ();
		reg_b = read8 (ea);
		inst_tst8 (reg_b);
		cycles += 4;
		break;
		
	case 0xe6:
		ea = ea_indexed (&cycles);
		reg_b = read8 (ea);
		inst_tst8 (reg_b);
		cycles += 4;
		break;
		
	case 0xf6:
		ea = ea_extended ();
		reg_b = read8 (ea);
		inst_tst8 (reg_b);
		cycles += 5;
		break;
		
	/* sta */
	case 0x97:
		ea = ea_direct ();
		write8 (ea, reg_a);
		inst_tst8 (reg_a);
		cycles += 4;
		break;
		
	case 0xa7:
		ea = ea_indexed (&cycles);
		write8 (ea, reg_a);
		inst_tst8 (reg_a);
		cycles += 4;
		break;
		
	case 0xb7:
		ea = ea_extended ();
		write8 (ea, reg_a);
		inst_tst8 (reg_a);
		cycles += 5;
		break;
		
	/* stb */
	case 0xd7:
		ea = ea_direct ();
		write8 (ea, reg_b);
		inst_tst8 (reg_b);
		cycles += 4;
		break;
		
	case 0xe7:
		ea = ea_indexed (&cycles);
		write8 (ea, reg_b);
		inst_tst8 (reg_b);
		cycles += 4;
		break;
		
	case 0xf7:
		ea = ea_extended ();
		write8 (ea, reg_b);
		inst_tst8 (reg_b);
		cycles += 5;
		break;
		
	/* eora */
	case 0x88:
		reg_a = inst_eor (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x98:
		ea = ea_direct ();
		reg_a = inst_eor (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xa8:
		ea = ea_indexed (&cycles);
		reg_a = inst_eor (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xb8:
		ea = ea_extended ();
		reg_a = inst_eor (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* eorb */
	case 0xc8:
		reg_b = inst_eor (reg_b, pc_read8 ());
		cycles += 2;
		break;
	case 0xd8:
		ea = ea_direct ();
		reg_b = inst_eor (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xe8:
		ea = ea_indexed (&cycles);
		reg_b = inst_eor (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xf8:
		ea = ea_extended ();
		reg_b = inst_eor (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* adca */
	case 0x89:
		reg_a = inst_adc (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x99:
		ea = ea_direct ();
		reg_a = inst_adc (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xa9:
		ea = ea_indexed (&cycles);
		reg_a = inst_adc (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xb9:
		ea = ea_extended ();
		reg_a = inst_adc (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* adcb */
	case 0xc9:
		reg_b = inst_adc (reg_b, pc_read8 ());
		cycles += 2;
		break;
		
	case 0xd9:
		ea = ea_direct ();
		reg_b = inst_adc (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xe9:
		ea = ea_indexed (&cycles);
		reg_b = inst_adc (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xf9:
		ea = ea_extended ();
		reg_b = inst_adc (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* ora */
	case 0x8a:
		reg_a = inst_or (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x9a:
		ea = ea_direct ();
		reg_a = inst_or (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xaa:
		ea = ea_indexed (&cycles);
		reg_a = inst_or (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xba:
		ea = ea_extended ();
		reg_a = inst_or (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* orb */
	case 0xca:
		reg_b = inst_or (reg_b, pc_read8 ());
		cycles += 2;
		break;
		
	case 0xda:
		ea = ea_direct ();
		reg_b = inst_or (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xea:
		ea = ea_indexed (&cycles);
		reg_b = inst_or (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xfa:
		ea = ea_extended ();
		reg_b = inst_or (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* adda */
	case 0x8b:
		reg_a = inst_add8 (reg_a, pc_read8 ());
		cycles += 2;
		break;
		
	case 0x9b:
		ea = ea_direct ();
		reg_a = inst_add8 (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xab:
		ea = ea_indexed (&cycles);
		reg_a = inst_add8 (reg_a, read8 (ea));
		cycles += 4;
		break;
		
	case 0xbb:
		ea = ea_extended ();
		reg_a = inst_add8 (reg_a, read8 (ea));
		cycles += 5;
		break;
		
	/* addb */
	case 0xcb:
		reg_b = inst_add8 (reg_b, pc_read8 ());
		cycles += 2;
		break;
		
	case 0xdb:
		ea = ea_direct ();
		reg_b = inst_add8 (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xeb:
		ea = ea_indexed (&cycles);
		reg_b = inst_add8 (reg_b, read8 (ea));
		cycles += 4;
		break;
		
	case 0xfb:
		ea = ea_extended ();
		reg_b = inst_add8 (reg_b, read8 (ea));
		cycles += 5;
		break;
		
	/* subd */
	case 0x83:
		set_reg_d (inst_sub16 (get_reg_d (), pc_read16 ()));
		cycles += 4;
		break;
		
	case 0x93:
		ea = ea_direct ();
		set_reg_d (inst_sub16 (get_reg_d (), read16 (ea)));
		cycles += 6;
		break;
		
	case 0xa3:
		ea = ea_indexed (&cycles);
		set_reg_d (inst_sub16 (get_reg_d (), read16 (ea)));
		cycles += 6;
		break;
		
	case 0xb3:
		ea = ea_extended ();
		set_reg_d (inst_sub16 (get_reg_d (), read16 (ea)));
		cycles += 7;
		break;
		
	/* cmpx */
	case 0x8c:
		inst_sub16 (reg_x, pc_read16 ());
		cycles += 4;
		break;
		
	case 0x9c:
		ea = ea_direct ();
		inst_sub16 (reg_x, read16 (ea));
		cycles += 6;
		break;
		
	case 0xac:
		ea = ea_indexed (&cycles);
		inst_sub16 (reg_x, read16 (ea));
		cycles += 6;
		break;
		
	case 0xbc:
		ea = ea_extended ();
		inst_sub16 (reg_x, read16 (ea));
		cycles += 7;
		break;
		
	/* ldx */
	case 0x8e:
		reg_x = pc_read16 ();
		inst_tst16 (reg_x);
		cycles += 3;
		break;
		
	case 0x9e: 
		ea = ea_direct ();
		reg_x = read16 (ea);
		inst_tst16 (reg_x);
		cycles += 5;
		break;
		
	case 0xae:
		ea = ea_indexed (&cycles);
		reg_x = read16 (ea);
		inst_tst16 (reg_x);
		cycles += 5;
		break;
		
	case 0xbe:
		ea = ea_extended ();
		reg_x = read16 (ea);
		inst_tst16 (reg_x);
		cycles += 6;
		break;
		
	/* ldu */
	case 0xce:
		reg_u = pc_read16 ();
		inst_tst16 (reg_u);
		cycles += 3;
		break;
		
	case 0xde: 
		ea = ea_direct ();
		reg_u = read16 (ea);
		inst_tst16 (reg_u);
		cycles += 5;
		break;
		
	case 0xee:
		ea = ea_indexed (&cycles);
		reg_u = read16 (ea);
		inst_tst16 (reg_u);
		cycles += 5;
		break;
		
	case 0xfe:
		ea = ea_extended ();
		reg_u = read16 (ea);
		inst_tst16 (reg_u);
		cycles += 6;
		break;
		
	/* stx */
	case 0x9f:
		ea = ea_direct ();
		write16 (ea, reg_x);
		inst_tst16 (reg_x);
		cycles += 5;
		break;
		
	case 0xaf:
		ea = ea_indexed (&cycles);
		write16 (ea, reg_x);
		inst_tst16 (reg_x);
		cycles += 5;
		break;
		
	case 0xbf:
		ea = ea_extended ();
		write16 (ea, reg_x);
		inst_tst16 (reg_x);
		cycles += 6;
		break;
		
	/* stu */
	case 0xdf:
		ea = ea_direct ();
		write16 (ea, reg_u);
		inst_tst16 (reg_u);
		cycles += 5;
		break;
		
	case 0xef:
		ea = ea_indexed (&cycles);
		write16 (ea, reg_u);
		inst_tst16 (reg_u);
		cycles += 5;
		break;
		
	case 0xff:
		ea = ea_extended ();
		write16 (ea, reg_u);
		inst_tst16 (reg_u);
		cycles += 6;
		break;
		
	/* addd */
	case 0xc3:
		set_reg_d (inst_add16 (get_reg_d (), pc_read16 ()));
		cycles += 4;
		break;
		
	case 0xd3:
		ea = ea_direct ();
		set_reg_d (inst_add16 (get_reg_d (), read16 (ea)));
		cycles += 6;
		break;
		
	case 0xe3:
		ea = ea_indexed (&cycles);
		set_reg_d (inst_add16 (get_reg_d (), read16 (ea)));
		cycles += 6;
		break;
		
	case 0xf3:
		ea = ea_extended ();
		set_reg_d (inst_add16 (get_reg_d (), read16 (ea)));
		cycles += 7;
		break;
		
	/* ldd */
	case 0xcc:
		set_reg_d (pc_read16 ());
		inst_tst16 (get_reg_d ());
		cycles += 3;
		break;
		
	case 0xdc: 
		ea = ea_direct ();
		set_reg_d (read16 (ea));
		inst_tst16 (get_reg_d ());
		cycles += 5;
		break;
		
	case 0xec:
		ea = ea_indexed (&cycles);
		set_reg_d (read16 (ea));
		inst_tst16 (get_reg_d ());
		cycles += 5;
		break;
		
	case 0xfc:
		ea = ea_extended ();
		set_reg_d (read16 (ea));
		inst_tst16 (get_reg_d ());
		cycles += 6;
		break;
		
	/* std */
	case 0xdd:
		ea = ea_direct ();
		write16 (ea, get_reg_d ());
		inst_tst16 (get_reg_d ());
		cycles += 5;
		break;
		
	case 0xed:
		ea = ea_indexed (&cycles);
		write16 (ea, get_reg_d ());
		inst_tst16 (get_reg_d ());
		cycles += 5;
		break;
		
	case 0xfd:
		ea = ea_extended ();
		write16 (ea, get_reg_d ());
		inst_tst16 (get_reg_d ());
		cycles += 6;
		break;
		
	/* nop */
	case 0x12:
		cycles += 2;
		break;
		
	/* mul */
	case 0x3d:
		r = (reg_a & 0xff) * (reg_b & 0xff);
		set_reg_d (r);

		set_cc (FLAG_Z, test_z16 (r));
		set_cc (FLAG_C, (r >> 7) & 1);
		
		cycles += 11;
		break;
		
	/* bra */
	case 0x20:
	/* brn */
	case 0x21:
		inst_bra8 (0, op, &cycles);
		break;
		
	/* bhi */
	case 0x22:
	/* bls */
	case 0x23:
		inst_bra8 (get_cc (FLAG_C) | get_cc (FLAG_Z), op, &cycles);
		break;
		
	/* bhs/bcc */
	case 0x24:
	/* blo/bcs */
	case 0x25:
		inst_bra8 (get_cc (FLAG_C), op, &cycles);
		break;
		
	/* bne */
	case 0x26:
	/* beq */
	case 0x27:
		inst_bra8 (get_cc (FLAG_Z), op, &cycles);
		break;
		
	/* bvc */
	case 0x28:
	/* bvs */
	case 0x29:
		inst_bra8 (get_cc (FLAG_V), op, &cycles);
		break;
		
	/* bpl */
	case 0x2a:
	/* bmi */
	case 0x2b:
		inst_bra8 (get_cc (FLAG_N), op, &cycles);
		break;
		
	/* bge */
	case 0x2c:
	/* blt */
	case 0x2d:
		inst_bra8 (get_cc (FLAG_N) ^ get_cc (FLAG_V), op, &cycles);
		break;
		
	/* bgt */
	case 0x2e:
	/* ble */
	case 0x2f:
		inst_bra8 (get_cc (FLAG_Z) |
				   (get_cc (FLAG_N) ^ get_cc (FLAG_V)), op, &cycles);
		break;
		
	/* lbra */
	case 0x16:
		r = pc_read16 ();
		reg_pc += r;
		cycles += 5;
		break;
		
	/* lbsr */
	case 0x17:
		r = pc_read16 ();
		push16 (&reg_s, reg_pc);
		reg_pc += r;
		cycles += 9;
		break;
		
	/* bsr */
	case 0x8d:
		r = pc_read8 ();
		push16 (&reg_s, reg_pc);
		reg_pc += sign_extend (r);
		cycles += 7;
		break;
		
	/* jsr */
	case 0x9d:
		ea = ea_direct ();
		push16 (&reg_s, reg_pc);
		reg_pc = ea;
		cycles += 7;
		break;
		
	case 0xad:
		ea = ea_indexed (&cycles);
		push16 (&reg_s, reg_pc);
		reg_pc = ea;
		cycles += 7;
		break;
		
	case 0xbd:
		ea = ea_extended ();
		push16 (&reg_s, reg_pc);
		reg_pc = ea;
		cycles += 8;
		break;
		
	/* leax */
	case 0x30:
		reg_x = ea_indexed (&cycles);
		set_cc (FLAG_Z, test_z16 (reg_x));
		cycles += 4;
		break;
		
	/* leay */
	case 0x31:
		reg_y = ea_indexed (&cycles);
		set_cc (FLAG_Z, test_z16 (reg_y));
		cycles += 4;
		break;
		
	/* leas */
	case 0x32:
		reg_s = ea_indexed (&cycles);
		cycles += 4;
		break;
		
	/* leau */
	case 0x33:
		reg_u = ea_indexed (&cycles);
		cycles += 4;
		break;
		
	/* pshs */
	case 0x34:
		inst_psh (pc_read8 (), &reg_s, reg_u, &cycles);
		cycles += 5;
		break;
		
	/* puls */
	case 0x35:
		inst_pul (pc_read8 (), &reg_s, &reg_u, &cycles);
		cycles += 5;
		break;
		
	/* pshu */
	case 0x36:
		inst_psh (pc_read8 (), &reg_u, reg_s, &cycles);
		cycles += 5;
		break;
		
	/* pulu */
	case 0x37:
		inst_pul (pc_read8 (), &reg_u, &reg_s, &cycles);
		cycles += 5;
		break;
		
	/* rts */
	case 0x39:
		reg_pc = pull16 (&reg_s);
		cycles += 5;
		break;
		
	/* abx */
	case 0x3a:
		reg_x += reg_b & 0xff;
		cycles += 3;
		break;
		
	/* orcc */
	case 0x1a:
		reg_cc |= pc_read8 ();
		cycles += 3;
		break;
		
	/* andcc */
	case 0x1c:
		reg_cc &= pc_read8 ();
		cycles += 3;
		break;
		
	/* sex */
	case 0x1d:
		set_reg_d (sign_extend (reg_b));
		set_cc (FLAG_N, test_n (reg_a));
		set_cc (FLAG_Z, test_z16 (get_reg_d ()));
		cycles += 2;
		break;
		
	/* exg */
	case 0x1e:
		inst_exg ();
		cycles += 8;
		break;
		
	/* tfr */
	case 0x1f:
		inst_tfr ();
		cycles += 6;
		break;
		
	/* rti */
	case 0x3b:
		if (get_cc (FLAG_E)) {
			inst_pul (0xff, &reg_s, &reg_u, &cycles);
		} else {
			inst_pul (0x81, &reg_s, &reg_u, &cycles);
		}

		cycles += 3;
		break;
		
	/* swi */
	case 0x3f:
		set_cc (FLAG_E, 1);
		inst_psh (0xff, &reg_s, reg_u, &cycles);
		set_cc (FLAG_I, 1);
		set_cc (FLAG_F, 1);
        reg_pc = read16 (0xfffa);
        cycles += 7;
		break;
		
	/* sync */
	case 0x13:
		irq_status = IRQ_SYNC;
		cycles += 2;
		break;
		
	/* daa */
	case 0x19:
		i0 = reg_a;
		i1 = 0;

		if ((reg_a & 0x0f) > 0x09 || get_cc (FLAG_H) == 1) {
			i1 |= 0x06;
		}

		if ((reg_a & 0xf0) > 0x80 && (reg_a & 0x0f) > 0x09) {
			i1 |= 0x60;
		}

		if ((reg_a & 0xf0) > 0x90 || get_cc (FLAG_C) == 1) {
			i1 |= 0x60;
		}

		reg_a = i0 + i1;

		set_cc (FLAG_N, test_n (reg_a));
		set_cc (FLAG_Z, test_z8 (reg_a));
		set_cc (FLAG_V, 0);
		set_cc (FLAG_C, test_c (i0, i1, reg_a, 0));
		cycles += 2;
		break;
		
	/* cwai */
	case 0x3c:
		reg_cc &= pc_read8 ();
		set_cc (FLAG_E, 1);
		inst_psh (0xff, &reg_s, reg_u, &cycles);
		irq_status = IRQ_CWAI;
		cycles += 4;
		break;

	/* page 1 instructions */

	case 0x10:
		op = pc_read8 ();

		switch (op) {
		/* lbra */
		case 0x20:
		/* lbrn */
		case 0x21:
			inst_bra16 (0, op, &cycles);
			break;
			
		/* lbhi */
		case 0x22:
		/* lbls */
		case 0x23:
			inst_bra16 (get_cc (FLAG_C) | get_cc (FLAG_Z), op, &cycles);
			break;
			
		/* lbhs/lbcc */
		case 0x24:
		/* lblo/lbcs */
		case 0x25:
			inst_bra16 (get_cc (FLAG_C), op, &cycles);
			break;
			
		/* lbne */
		case 0x26:
		/* lbeq */
		case 0x27:
			inst_bra16 (get_cc (FLAG_Z), op, &cycles);
			break;
			
		/* lbvc */
		case 0x28:
		/* lbvs */
		case 0x29:
			inst_bra16 (get_cc (FLAG_V), op, &cycles);
			break;
			
		/* lbpl */
		case 0x2a:
		/* lbmi */
		case 0x2b:
			inst_bra16 (get_cc (FLAG_N), op, &cycles);
			break;
			
		/* lbge */
		case 0x2c:
		/* lblt */
		case 0x2d:
			inst_bra16 (get_cc (FLAG_N) ^ get_cc (FLAG_V), op, &cycles);
			break;
			
		/* lbgt */
		case 0x2e:
		/* lble */
		case 0x2f:
			inst_bra16 (get_cc (FLAG_Z) |
						(get_cc (FLAG_N) ^ get_cc (FLAG_V)), op, &cycles);
			break;
			
		/* cmpd */
		case 0x83:
			inst_sub16 (get_reg_d (), pc_read16 ());
			cycles += 5;
			break;
			
		case 0x93:
			ea = ea_direct ();
			inst_sub16 (get_reg_d (), read16 (ea));
			cycles += 7;
			break;
			
		case 0xa3:
			ea = ea_indexed (&cycles);
			inst_sub16 (get_reg_d (), read16 (ea));
			cycles += 7;
			break;
			
		case 0xb3:
			ea = ea_extended ();
			inst_sub16 (get_reg_d (), read16 (ea));
			cycles += 8;
			break;
			
		/* cmpy */
		case 0x8c:
			inst_sub16 (reg_y, pc_read16 ());
			cycles += 5;
			break;
			
		case 0x9c:
			ea = ea_direct ();
			inst_sub16 (reg_y, read16 (ea));
			cycles += 7;
			break;
			
		case 0xac:
			ea = ea_indexed (&cycles);
			inst_sub16 (reg_y, read16 (ea));
			cycles += 7;
			break;
			
		case 0xbc:
			ea = ea_extended ();
			inst_sub16 (reg_y, read16 (ea));
			cycles += 8;
			break;
			
		/* ldy */
		case 0x8e:
			reg_y = pc_read16 ();
			inst_tst16 (reg_y);
			cycles += 4;
			break;
			
		case 0x9e: 
			ea = ea_direct ();
			reg_y = read16 (ea);
			inst_tst16 (reg_y);
			cycles += 6;
			break;
			
		case 0xae:
			ea = ea_indexed (&cycles);
			reg_y = read16 (ea);
			inst_tst16 (reg_y);
			cycles += 6;
			break;
			
		case 0xbe:
			ea = ea_extended ();
			reg_y = read16 (ea);
			inst_tst16 (reg_y);
			cycles += 7;
			break;
			
		/* sty */
		case 0x9f:
			ea = ea_direct ();
			write16 (ea, reg_y);
			inst_tst16 (reg_y);
			cycles += 6;
			break;
			
		case 0xaf:
			ea = ea_indexed (&cycles);
			write16 (ea, reg_y);
			inst_tst16 (reg_y);
			cycles += 6;
			break;
			
		case 0xbf:
			ea = ea_extended ();
			write16 (ea, reg_y);
			inst_tst16 (reg_y);
			cycles += 7;
			break;
			
		/* lds */
		case 0xce:
			reg_s = pc_read16 ();
			inst_tst16 (reg_s);
			cycles += 4;
			break;
			
		case 0xde: 
			ea = ea_direct ();
			reg_s = read16 (ea);
			inst_tst16 (reg_s);
			cycles += 6;
			break;
			
		case 0xee:
			ea = ea_indexed (&cycles);
			reg_s = read16 (ea);
			inst_tst16 (reg_s);
			cycles += 6;
			break;
			
		case 0xfe:
			ea = ea_extended ();
			reg_s = read16 (ea);
			inst_tst16 (reg_s);
			cycles += 7;
			break;
			
		/* sts */
		case 0xdf:
			ea = ea_direct ();
			write16 (ea, reg_s);
			inst_tst16 (reg_s);
			cycles += 6;
			break;
			
		case 0xef:
			ea = ea_indexed (&cycles);
			write16 (ea, reg_s);
			inst_tst16 (reg_s);
			cycles += 6;
			break;
			
		case 0xff:
			ea = ea_extended ();
			write16 (ea, reg_s);
			inst_tst16 (reg_s);
			cycles += 7;
			break;
			
		/* swi2 */
		case 0x3f:
			set_cc (FLAG_E, 1);
			inst_psh (0xff, &reg_s, reg_u, &cycles);
		    reg_pc = read16 (0xfff4);
			cycles += 8;
			break;
			
		default:
			/*printf ("unknown page-1 op code: %.2x\n", op);*/
			break;
		}

		break;

	/* page 2 instructions */

	case 0x11:
		op = pc_read8 ();

		switch (op) {
		/* cmpu */
		case 0x83:
			inst_sub16 (reg_u, pc_read16 ());
			cycles += 5;
			break;
			
		case 0x93:
			ea = ea_direct ();
			inst_sub16 (reg_u, read16 (ea));
			cycles += 7;
			break;
			
		case 0xa3:
			ea = ea_indexed (&cycles);
			inst_sub16 (reg_u, read16 (ea));
			cycles += 7;
			break;
			
		case 0xb3:
			ea = ea_extended ();
			inst_sub16 (reg_u, read16 (ea));
			cycles += 8;
			break;
			
		/* cmps */
		case 0x8c:
			inst_sub16 (reg_s, pc_read16 ());
			cycles += 5;
			break;
			
		case 0x9c:
			ea = ea_direct ();
			inst_sub16 (reg_s, read16 (ea));
			cycles += 7;
			break;
			
		case 0xac:
			ea = ea_indexed (&cycles);
			inst_sub16 (reg_s, read16 (ea));
			cycles += 7;
			break;
			
		case 0xbc:
			ea = ea_extended ();
			inst_sub16 (reg_s, read16 (ea));
			cycles += 8;
			break;
			
		/* swi3 */
		case 0x3f:
			set_cc (FLAG_E, 1);
			inst_psh (0xff, &reg_s, reg_u, &cycles);
		    reg_pc = read16 (0xfff2);
			cycles += 8;
			break;
			
		default:
			/*printf ("unknown page-2 op code: %.2x\n", op);*/
			break;
		}

		break;

	default:
		/*printf ("unknown page-0 op code: %.2x\n", op);*/
		break;
	}

	return cycles;
}

/**************************************
** CONTENT OF THE VECX.C FILE
**************************************/
unsigned char rom[8192];
unsigned char cart[32768];
static unsigned char ram[1024];

/* the sound chip registers */

unsigned snd_regs[16];
static unsigned snd_select;

/* the via 6522 registers */

static unsigned via_ora;
static unsigned via_orb;
static unsigned via_ddra;
static unsigned via_ddrb;
static unsigned via_t1on;  /* is timer 1 on? */
static unsigned via_t1int; /* are timer 1 interrupts allowed? */
static unsigned via_t1c;
static unsigned via_t1ll;
static unsigned via_t1lh;
static unsigned via_t1pb7; /* timer 1 controlled version of pb7 */
static unsigned via_t2on;  /* is timer 2 on? */
static unsigned via_t2int; /* are timer 2 interrupts allowed? */
static unsigned via_t2c;
static unsigned via_t2ll;
static unsigned via_sr;
static unsigned via_srb;   /* number of bits shifted so far */
static unsigned via_src;   /* shift counter */
static unsigned via_srclk;
static unsigned via_acr;
static unsigned via_pcr;
static unsigned via_ifr;
static unsigned via_ier;
static unsigned via_ca2;
static unsigned via_cb2h;  /* basic handshake version of cb2 */
static unsigned via_cb2s;  /* version of cb2 controlled by the shift register */

/* analog devices */

static unsigned alg_rsh;  /* zero ref sample and hold */
static unsigned alg_xsh;  /* x sample and hold */
static unsigned alg_ysh;  /* y sample and hold */
static unsigned alg_zsh;  /* z sample and hold */
unsigned alg_jch0;		  /* joystick direction channel 0 */
unsigned alg_jch1;		  /* joystick direction channel 1 */
unsigned alg_jch2;		  /* joystick direction channel 2 */
unsigned alg_jch3;		  /* joystick direction channel 3 */
static unsigned alg_jsh;  /* joystick sample and hold */

static unsigned alg_compare;

static long alg_dx;     /* delta x */
static long alg_dy;     /* delta y */
static long alg_curr_x; /* current x position */
static long alg_curr_y; /* current y position */

static unsigned alg_vectoring; /* are we drawing a vector right now? */
static long alg_vector_x0;
static long alg_vector_y0;
static long alg_vector_x1;
static long alg_vector_y1;
static long alg_vector_dx;
static long alg_vector_dy;
static unsigned char alg_vector_color;

long vector_draw_cnt;
long vector_erse_cnt;
static vector_t vectors_set[2 * VECTOR_CNT];
vector_t *vectors_draw;
vector_t *vectors_erse;

static long vector_hash[VECTOR_HASH];

static long fcycles;

/* update the snd chips internal registers when via_ora/via_orb changes */

static einline void snd_update (void)
{
	switch (via_orb & 0x18) {
	case 0x00:
		/* the sound chip is disabled */
		break;
		
	case 0x08:
		/* the sound chip is sending data */
		break;
		
	case 0x10:
		/* the sound chip is recieving data */
		if (snd_select != 14) {
			snd_regs[snd_select] = via_ora;
		}
		break;
		
	case 0x18:
		/* the sound chip is latching an address */
				if ((via_ora & 0xf0) == 0x00) {
			snd_select = via_ora & 0x0f;
		}
		break;
	}
}

/* update the various analog values when orb is written. */

static einline void alg_update (void)
{
	switch (via_orb & 0x06) {
	case 0x00:
		alg_jsh = alg_jch0;

		if ((via_orb & 0x01) == 0x00) {
			/* demultiplexor is on */
			alg_ysh = alg_xsh;
		}
		break;
		
	case 0x02:
		alg_jsh = alg_jch1;

		if ((via_orb & 0x01) == 0x00) {
			/* demultiplexor is on */
			alg_rsh = alg_xsh;
		}
		break;
		
	case 0x04:
		alg_jsh = alg_jch2;

		if ((via_orb & 0x01) == 0x00) {
			/* demultiplexor is on */

			if (alg_xsh > 0x80) {
				alg_zsh = alg_xsh - 0x80;
			} else {
				alg_zsh = 0;
			}
		}
		break;
		
	case 0x06:
		/* sound output line */
		alg_jsh = alg_jch3;
		break;
	}

	/* compare the current joystick direction with a reference */

	if (alg_jsh > alg_xsh) {
		alg_compare = 0x20;
	} else {
		alg_compare = 0;
	}

	/* compute the new "deltas" */

	alg_dx = (long) alg_xsh - (long) alg_rsh;
	alg_dy = (long) alg_rsh - (long) alg_ysh;
}

/* update IRQ and bit-7 of the ifr register after making an adjustment to
 * ifr.
 */

static einline void int_update (void)
{
	if ((via_ifr & 0x7f) & (via_ier & 0x7f)) {
		via_ifr |= 0x80;
	} else {
		via_ifr &= 0x7f;
	}
}

unsigned char read8 (unsigned address)
{
	/*ced*/ address &= 0xffff;
	
	unsigned char data;

	if ((address & 0xe000) == 0xe000) {
		/* rom */
		data = rom[address & 0x1fff];
	} else if ((address & 0xe000) == 0xc000) {
		if (address & 0x800) {
			/* ram */
			data = ram[address & 0x3ff];
		} else if (address & 0x1000) {
			/* io */
			switch (address & 0xf) {
			case 0x0:
				/* compare signal is an input so the value does not come from
				 * via_orb.
				 */
				if (via_acr & 0x80) {
					/* timer 1 has control of bit 7 */
					data = (unsigned char) ((via_orb & 0x5f) | via_t1pb7 | alg_compare);
				} else {
					/* bit 7 is being driven by via_orb */
					data = (unsigned char) ((via_orb & 0xdf) | alg_compare);
				}
				break;
				
			case 0x1:
				/* register 1 also performs handshakes if necessary */
				if ((via_pcr & 0x0e) == 0x08) {
					/* if ca2 is in pulse mode or handshake mode, then it
					 * goes low whenever ira is read.
					 */
					via_ca2 = 0;
				}

				/* fall through */
			case 0xf:
				if ((via_orb & 0x18) == 0x08) {
					/* the snd chip is driving port a */

					data = (unsigned char) snd_regs[snd_select];
				} else {
					data = (unsigned char) via_ora;
				}
				break;
				
			case 0x2:
				data = (unsigned char) via_ddrb;
				break;
				
			case 0x3:
				data = (unsigned char) via_ddra;
				break;
				
			case 0x4:
				/* T1 low order counter */
				
				data = (unsigned char) via_t1c;
				via_ifr &= 0xbf; /* remove timer 1 interrupt flag */

				via_t1on = 0; /* timer 1 is stopped */
				via_t1int = 0;
				via_t1pb7 = 0x80;

				int_update ();

				break;
				
			case 0x5:
				/* T1 high order counter */

				data = (unsigned char) (via_t1c >> 8);

				break;
				
			case 0x6:
				/* T1 low order latch */

				data = (unsigned char) via_t1ll;
				break;
				
			case 0x7:
				/* T1 high order latch */

				data = (unsigned char) via_t1lh;
				break;
				
			case 0x8:
				/* T2 low order counter */

				data = (unsigned char) via_t2c;
				via_ifr &= 0xdf; /* remove timer 2 interrupt flag */

				via_t2on = 0; /* timer 2 is stopped */
				via_t2int = 0;

				int_update ();

				break;
				
			case 0x9:
				/* T2 high order counter */

				data = (unsigned char) (via_t2c >> 8);
				break;
				
			case 0xa:
				data = (unsigned char) via_sr;
				via_ifr &= 0xfb; /* remove shift register interrupt flag */
				via_srb = 0;
				via_srclk = 1;

				int_update ();

				break;
				
			case 0xb:
				data = (unsigned char) via_acr;
				break;
			case 0xc:
				data = (unsigned char) via_pcr;
				break;
				
			case 0xd:
				/* interrupt flag register */

				data = (unsigned char) via_ifr;
				break;
				
			case 0xe:
				/* interrupt enable register */

				data = (unsigned char) (via_ier | 0x80);
				break;
			}
		}
	} else if (address < 0x8000) {
		/* cartridge */

		data = cart[address];
	} else {
		data = 0xff;
	}

	return data;
}

void write8 (unsigned address, unsigned char data)
{
	/*ced*/ address &= 0xffff;
	
	if ((address & 0xe000) == 0xe000) {
		/* rom */
	} else if ((address & 0xe000) == 0xc000) {
		/* it is possible for both ram and io to be written at the same! */
		if (address & 0x800) {
			ram[address & 0x3ff] = data;
		}

		if (address & 0x1000) {
			switch (address & 0xf) {
			case 0x0:
				via_orb = data;

				snd_update ();

				alg_update ();

				if ((via_pcr & 0xe0) == 0x80) {
					/* if cb2 is in pulse mode or handshake mode, then it
					 * goes low whenever orb is written.
					 */
					via_cb2h = 0;
				}

				break;
				
			case 0x1:
				/* register 1 also performs handshakes if necessary */
				if ((via_pcr & 0x0e) == 0x08) {
					/* if ca2 is in pulse mode or handshake mode, then it
					 * goes low whenever ora is written.
					 */

					via_ca2 = 0;
				}

				/* fall through */
			case 0xf:
				via_ora = data;

				snd_update ();

				/* output of port a feeds directly into the dac which then
				 * feeds the x axis sample and hold.
				 */
				alg_xsh = data ^ 0x80;

				alg_update ();

				break;
				
			case 0x2:
				via_ddrb = data;
				break;
				
			case 0x3:
				via_ddra = data;
				break;
				
			case 0x4:
				/* T1 low order counter */
				via_t1ll = data;

				break;
				
			case 0x5:
				/* T1 high order counter */
				via_t1lh = data;
				via_t1c = (via_t1lh << 8) | via_t1ll;
				via_ifr &= 0xbf; /* remove timer 1 interrupt flag */

				via_t1on = 1; /* timer 1 starts running */
				via_t1int = 1;
				via_t1pb7 = 0;

				int_update ();

				break;
				
			case 0x6:
				/* T1 low order latch */
				via_t1ll = data;
				break;
				
			case 0x7:
				/* T1 high order latch */
				via_t1lh = data;
				break;
				
			case 0x8:
				/* T2 low order latch */
				via_t2ll = data;
				break;
				
			case 0x9:
				/* T2 high order latch/counter */
				via_t2c = (data << 8) | via_t2ll;
				via_ifr &= 0xdf;

				via_t2on = 1; /* timer 2 starts running */
				via_t2int = 1;

				int_update ();

				break;
				
			case 0xa:
				via_sr = data;
				via_ifr &= 0xfb; /* remove shift register interrupt flag */
				via_srb = 0;
				via_srclk = 1;

				int_update ();

				break;
				
			case 0xb:
				via_acr = data;
				break;
				
			case 0xc:
				via_pcr = data;


				if ((via_pcr & 0x0e) == 0x0c) {
					/* ca2 is outputting low */
					via_ca2 = 0;
				} else {
					/* ca2 is disabled or in pulse mode or is
					 * outputting high.
					 */
					via_ca2 = 1;
				}

				if ((via_pcr & 0xe0) == 0xc0) {
					/* cb2 is outputting low */
					via_cb2h = 0;
				} else {
					/* cb2 is disabled or is in pulse mode or is
					 * outputting high.
					 */
					via_cb2h = 1;
				}

				break;
				
			case 0xd:
				/* interrupt flag register */
				via_ifr &= ~(data & 0x7f);
				int_update ();

				break;
				
			case 0xe:
				/* interrupt enable register */
				if (data & 0x80) {
					via_ier |= data & 0x7f;
				} else {
					via_ier &= ~(data & 0x7f);
				}

				int_update ();

				break;
			}
		}
	} else if (address < 0x8000) {
		/* cartridge */
	}
}

void vecx_reset (void)
{
	unsigned r;

	/* ram */
	for (r = 0; r < 1024; r++) {
		ram[r] = r & 0xff;
	}

	for (r = 0; r < 16; r++) {
		snd_regs[r] = 0;
	}

	/* input buttons */
	snd_regs[14] = 0xff;

	snd_select = 0;

	via_ora = 0;
	via_orb = 0;
	via_ddra = 0;
	via_ddrb = 0;
	via_t1on = 0;
	via_t1int = 0;
	via_t1c = 0;
	via_t1ll = 0;
	via_t1lh = 0;
	via_t1pb7 = 0x80;
	via_t2on = 0;
	via_t2int = 0; 
	via_t2c = 0;
	via_t2ll = 0;
	via_sr = 0;
	via_srb = 8;
	via_src = 0;
	via_srclk = 0;
	via_acr = 0;
	via_pcr = 0;
	via_ifr = 0;
	via_ier = 0;
	via_ca2 = 1;
	via_cb2h = 1;
	via_cb2s = 0;

	alg_rsh = 128;
	alg_xsh = 128;
	alg_ysh = 128;
	alg_zsh = 0;
	alg_jch0 = 128;
	alg_jch1 = 128;
	alg_jch2 = 128;
	alg_jch3 = 128;
	alg_jsh = 128;

	alg_compare = 0; /* check this */

	alg_dx = 0;
	alg_dy = 0;
	alg_curr_x = ALG_MAX_X / 2;
	alg_curr_y = ALG_MAX_Y / 2;

	alg_vectoring = 0;

	vector_draw_cnt = 0;
	vector_erse_cnt = 0;
	vectors_draw = vectors_set;
	vectors_erse = vectors_set + VECTOR_CNT;
	
	fcycles = VECTREX_CYCLES_BEFORE_VECTREX_REDRAW;

	e6809_read8 = read8;
	e6809_write8 = write8;

	e6809_reset ();
}

/* perform a single cycle worth of via emulation.
 * via_sstep0 is the first postion of the emulation.
 */
static einline void via_sstep0 (void)
{
	unsigned t2shift;

	if (via_t1on) {
		via_t1c--;

		if ((via_t1c & 0xffff) == 0xffff) {
			/* counter just rolled over */
			if (via_acr & 0x40) {
				/* continuous interrupt mode */
				via_ifr |= 0x40;
				int_update ();
				via_t1pb7 = 0x80 - via_t1pb7;

				/* reload counter */
				via_t1c = (via_t1lh << 8) | via_t1ll;
			} else {
				/* one shot mode */
				if (via_t1int) {
					via_ifr |= 0x40;
					int_update ();
					via_t1pb7 = 0x80;
					via_t1int = 0;
				}
			}
		}
	}

	if (via_t2on && (via_acr & 0x20) == 0x00) {
		via_t2c--;

		if ((via_t2c & 0xffff) == 0xffff) {
			/* one shot mode */
			if (via_t2int) {
				via_ifr |= 0x20;
				int_update ();
				via_t2int = 0;
			}
		}
	}

	/* shift counter */
	via_src--;

	if ((via_src & 0xff) == 0xff) {
		via_src = via_t2ll;

		if (via_srclk) {
			t2shift = 1;
			via_srclk = 0;
		} else {
			t2shift = 0;
			via_srclk = 1;
		}
	} else {
		t2shift = 0;
	}

	if (via_srb < 8) {
		switch (via_acr & 0x1c) {
		case 0x00:
			/* disabled */
			break;
		case 0x04:
			/* shift in under control of t2 */
			if (t2shift) {
				/* shifting in 0s since cb2 is always an output */
				via_sr <<= 1;
				via_srb++;
			}

			break;
			
		case 0x08:
			/* shift in under system clk control */
			via_sr <<= 1;
			via_srb++;

			break;
			
		case 0x0c:
			/* shift in under cb1 control */
			break;
			
		case 0x10:
			/* shift out under t2 control (free run) */
			if (t2shift) {
				via_cb2s = (via_sr >> 7) & 1;

				via_sr <<= 1;
				via_sr |= via_cb2s;
			}

			break;
			
		case 0x14:
			/* shift out under t2 control */
			if (t2shift) {
				via_cb2s = (via_sr >> 7) & 1;

				via_sr <<= 1;
				via_sr |= via_cb2s;
				via_srb++;
			}

			break;
			
		case 0x18:
			/* shift out under system clock control */

			via_cb2s = (via_sr >> 7) & 1;

			via_sr <<= 1;
			via_sr |= via_cb2s;
			via_srb++;

			break;
			
		case 0x1c:
			/* shift out under cb1 control */
			break;
		}

		if (via_srb == 8) {
			via_ifr |= 0x04;
			int_update ();
		}
	}
}

/* perform the second part of the via emulation */

static einline void via_sstep1 (void)
{
	if ((via_pcr & 0x0e) == 0x0a) {
		/* if ca2 is in pulse mode, then make sure
		 * it gets restored to '1' after the pulse.
		 */
		via_ca2 = 1;
	}

	if ((via_pcr & 0xe0) == 0xa0) {
		/* if cb2 is in pulse mode, then make sure
		 * it gets restored to '1' after the pulse.
		 */
		via_cb2h = 1;
	}
}

static einline void alg_addline (long x0, long y0, long x1, long y1, unsigned char color)
{
	unsigned long key;
	long index;

	key = (unsigned long) x0;
	key = key * 31 + (unsigned long) y0;
	key = key * 31 + (unsigned long) x1;
	key = key * 31 + (unsigned long) y1;
	key %= VECTOR_HASH;

	/* first check if the line to be drawn is in the current draw list.
	 * if it is, then it is not added again.
	 */
	index = vector_hash[key];

	if (index >= 0 && index < vector_draw_cnt &&
		x0 == vectors_draw[index].x0 &&
		y0 == vectors_draw[index].y0 &&
		x1 == vectors_draw[index].x1 &&
		y1 == vectors_draw[index].y1) {
		vectors_draw[index].color = color;
	} else {
		/* missed on the draw list, now check if the line to be drawn is in
		 * the erase list ... if it is, "invalidate" it on the erase list.
		 */
		if (index >= 0 && index < vector_erse_cnt &&
			x0 == vectors_erse[index].x0 &&
			y0 == vectors_erse[index].y0 &&
			x1 == vectors_erse[index].x1 &&
			y1 == vectors_erse[index].y1) {
			vectors_erse[index].color = VECTREX_COLORS;
		}

		vectors_draw[vector_draw_cnt].x0 = x0;
		vectors_draw[vector_draw_cnt].y0 = y0;
		vectors_draw[vector_draw_cnt].x1 = x1;
		vectors_draw[vector_draw_cnt].y1 = y1;
		vectors_draw[vector_draw_cnt].color = color;
		vector_hash[key] = vector_draw_cnt;
		vector_draw_cnt++;
	}
}

/* perform a single cycle worth of analog emulation */
static einline void alg_sstep (void)
{
	long sig_dx, sig_dy;
	unsigned sig_ramp;
	unsigned sig_blank;

	if ((via_acr & 0x10) == 0x10) {
		sig_blank = via_cb2s;
	} else {
		sig_blank = via_cb2h;
	}

	if (via_ca2 == 0) {
		/* need to force the current point to the 'orgin' so just
		 * calculate distance to origin and use that as dx,dy.
		 */
		sig_dx = ALG_MAX_X / 2 - alg_curr_x;
		sig_dy = ALG_MAX_Y / 2 - alg_curr_y;
	} else {
		if (via_acr & 0x80) {
			sig_ramp = via_t1pb7;
		} else {
			sig_ramp = via_orb & 0x80;
		}

		if (sig_ramp == 0) {
			sig_dx = alg_dx;
			sig_dy = alg_dy;
		} else {
			sig_dx = 0;
			sig_dy = 0;
		}
	}

	if (alg_vectoring == 0) {
		if (sig_blank == 1 &&
			alg_curr_x >= 0 && alg_curr_x < ALG_MAX_X &&
			alg_curr_y >= 0 && alg_curr_y < ALG_MAX_Y) {

			/* start a new vector */
			alg_vectoring = 1;
			alg_vector_x0 = alg_curr_x;
			alg_vector_y0 = alg_curr_y;
			alg_vector_x1 = alg_curr_x;
			alg_vector_y1 = alg_curr_y;
			alg_vector_dx = sig_dx;
			alg_vector_dy = sig_dy;
			alg_vector_color = (unsigned char) alg_zsh;
		}
	} else {
		/* already drawing a vector ... check if we need to turn it off */
		if (sig_blank == 0) {
			/* blank just went on, vectoring turns off, and we've got a
			 * new line.
			 */
			alg_vectoring = 0;

			alg_addline (alg_vector_x0, alg_vector_y0,
						 alg_vector_x1, alg_vector_y1,
						 alg_vector_color);
		} else if (sig_dx != alg_vector_dx ||
				   sig_dy != alg_vector_dy ||
				   (unsigned char) alg_zsh != alg_vector_color) {

			/* the parameters of the vectoring processing has changed.
			 * so end the current line.
			 */
			alg_addline (alg_vector_x0, alg_vector_y0,
						 alg_vector_x1, alg_vector_y1,
						 alg_vector_color);

			/* we continue vectoring with a new set of parameters if the
			 * current point is not out of limits.
			 */
			if (alg_curr_x >= 0 && alg_curr_x < ALG_MAX_X &&
				alg_curr_y >= 0 && alg_curr_y < ALG_MAX_Y) {
				alg_vector_x0 = alg_curr_x;
				alg_vector_y0 = alg_curr_y;
				alg_vector_x1 = alg_curr_x;
				alg_vector_y1 = alg_curr_y;
				alg_vector_dx = sig_dx;
				alg_vector_dy = sig_dy;
				alg_vector_color = (unsigned char) alg_zsh;
			} else {
				alg_vectoring = 0;
			}
		}
	}

	alg_curr_x += sig_dx;
	alg_curr_y += sig_dy;

	if (alg_vectoring == 1 &&
		alg_curr_x >= 0 && alg_curr_x < ALG_MAX_X &&
		alg_curr_y >= 0 && alg_curr_y < ALG_MAX_Y) {

		/* we're vectoring ... current point is still within limits so
		 * extend the current vector.
		 */
		alg_vector_x1 = alg_curr_x;
		alg_vector_y1 = alg_curr_y;
	}
}

long vecx_emu (long cycles_to_do)
{
	unsigned c, cycles_done;
	
	while (cycles_to_do > 0)
	{
		cycles_done = e6809_sstep (via_ifr & 0x80, 0);

		for (c = 0; c < cycles_done; c++)
		{
			via_sstep0 ();
			alg_sstep ();
			via_sstep1 ();
		}

		cycles_to_do -= (long) cycles_done;
		fcycles -= (long) cycles_done;

		if (fcycles < 0)
		{
			vector_t *tmp;
			
			osint_render ();
			
			fcycles += VECTREX_CYCLES_BEFORE_VECTREX_REDRAW;
			
			/* everything that was drawn during this pass now now enters
			* the erase list for the next pass.
			*/
			vector_erse_cnt = vector_draw_cnt;
			vector_draw_cnt = 0;
			
			tmp = vectors_erse;
			vectors_erse = vectors_draw;
			vectors_draw = tmp;
		}
	}
	
	return cycles_to_do;
}


/**************************************
** CONTENT OF THE OSINT.C FILE
**************************************/
/* a global string buffer user for message output */
char gbuffer[1024];

static long screen_x;
static long screen_y;
static long scl_factor;

/*static DWORD color_set[VECTREX_COLORS];*/

static void osint_updatescale (void)
{
	long sclx, scly;
	
	sclx = ALG_MAX_X / screen_x;
	scly = ALG_MAX_Y / screen_y;

	if (sclx > scly) {
		scl_factor = sclx;
	} else {
		scl_factor = scly;
	}
}

static int osint_defaults (void)
{
	unsigned b;
	int rom_file = 0;

	screen_x = LCD_HEIGHT /*330*/;
	screen_y = LCD_WIDTH /*410*/;

	osint_updatescale ();

	/* load up the rom */
	rom_file = rb->open (ROM_NAME, O_RDONLY);

	if (rom_file < 0) {
		rb->snprintf (gbuffer, sizeof(gbuffer), "cannot open '%s'", ROM_NAME);
		rb->splash(HZ*4, true, gbuffer);
		return 1;
	}

	b = rb->read (rom_file, rom, sizeof (rom));

	if (b < sizeof (rom)) {
		rb->snprintf (gbuffer, sizeof(gbuffer), "read %d bytes from '%s'. need %d bytes.",
			b, ROM_NAME, sizeof (rom));
		rb->splash(HZ*4, true, gbuffer);
		return 1;
	}

	rb->close (rom_file);

	/* the cart is empty by default */
	for (b = 0; b < sizeof (cart); b++) {
		cart[b] = 0;
	}

	return 0;
}


static void osint_load_cart (char *cartname)
{
	int cartfile = 0;
	
	cartfile = rb->open (cartname, O_RDONLY);
	
	if (cartfile >= 0)
	{
		rb->read (cartfile, cart, sizeof (cart));
		rb->close (cartfile);
	}
	else
	{
		rb->snprintf (gbuffer, sizeof(gbuffer), "cannot open '%s'", cartname);
		rb->splash(HZ*4, true, gbuffer);
	}
}

/*
static void osint_maskinfo (DWORD mask, int *shift, int *precision)
{
	*shift = 0;

	while ((mask & 1L) == 0) {
		mask >>= 1;
		(*shift)++;
	}

	*precision = 0;

	while ((mask & 1L) != 0) {
		mask >>= 1;
		(*precision)++;
	}
}
*/
/*
static void osint_gencolors (void)
{
	int c;
	int rcomp, gcomp, bcomp;
	int rsh, rpr;
	int gsh, gpr;
	int bsh, bpr;

	DDPIXELFORMAT ddpf;

	ddpf.dwSize = sizeof (ddpf);
	IDirectDrawSurface_GetPixelFormat (lpdd_primary, &ddpf);

	bytes_per_pixel = ddpf.dwRGBBitCount / 8;
	
	osint_maskinfo (ddpf.dwRBitMask, &rsh, &rpr);
	osint_maskinfo (ddpf.dwGBitMask, &gsh, &gpr);
	osint_maskinfo (ddpf.dwBBitMask, &bsh, &bpr);

	for (c = 0; c < VECTREX_COLORS; c++) {
		rcomp = c * 256 / VECTREX_COLORS;
		gcomp = c * 256 / VECTREX_COLORS;
		bcomp = c * 256 / VECTREX_COLORS;

		color_set[c] =	(((DWORD) rcomp >> (8 - rpr)) << rsh) |
						(((DWORD) gcomp >> (8 - gpr)) << gsh) |
						(((DWORD) bcomp >> (8 - bpr)) << bsh);
	}
}
*/

static einline void osint_clearscreen (void)
{
	rb->lcd_clear_display();
}

static void osint_line (long x0, long y0, long x1, long y1, unsigned char color)
{
	color = 0; /* unused param, do this to avoid a warning */
	
	/* non scaled version (iRiver screen is much too small for this one) */
	/*rb->lcd_drawline(x0, y0, x1, y1);*/
	
	/* scaled version (too small on 'landscape' screens, i.e. iRiver) */
	/* rb->lcd_drawline(x0 / scl_factor, y0 / scl_factor, x1 / scl_factor, y1 / scl_factor); */
	
	/* trick to rotate the display by 90° CCW (joystick on the left on iRiver) */
	/*rb->lcd_drawline((y0 / scl_factor) , LCD_HEIGHT-1 - (x0 / scl_factor), (y1 / scl_factor), LCD_HEIGHT-1 - (x1 / scl_factor));*/
	
	/* trick to rotate the display by 90° CW (joystick on the right on iRiver) */
	rb->lcd_drawline(LCD_WIDTH-1 - (y0 / scl_factor) , (x0 / scl_factor), LCD_WIDTH-1 - (y1 / scl_factor), (x1 / scl_factor));
}

void osint_render (void)
{
	long v, tmp_tick;

	osint_clearscreen ();

	for (v = 0; v < vector_erse_cnt; v++)
	{
		if (vectors_erse[v].color != VECTREX_COLORS)
		{
			osint_line (vectors_erse[v].x0, vectors_erse[v].y0, 
			            vectors_erse[v].x1, vectors_erse[v].y1, 0);
		}
	}

	for (v = 0; v < vector_draw_cnt; v++)
	{
		osint_line (vectors_draw[v].x0, vectors_draw[v].y0,
					vectors_draw[v].x1, vectors_draw[v].y1,
					vectors_draw[v].color);
	}

	/* keep FPS */
	vectrex_fps++;
	if ((tmp_tick = *rb->current_tick) >= next_vectrex_fps_update)
	{
		current_vectrex_fps = vectrex_fps;
		next_vectrex_fps_update = tmp_tick + HZ;
		vectrex_fps = 0;
	}	
}

void osint_emuloop (void)
{
	long time_to_run = 0;
	long time_to_display = 0;
	long remaining_cycles = 0;
	long tmp_tick;
	
	/* reset the vectrex hardware */
	vecx_reset ();

	for (;;)
	{
		/* is it time to continue emulation ??? */
		while ((tmp_tick = *rb->current_tick) < time_to_run)
			rb->yield();
		time_to_run = tmp_tick + LOCAL_TICKS_BEFORE_EMU_TIMER;
		
		/* emulate vectrex cycles between 2 "timers" */
		remaining_cycles = vecx_emu (VECTREX_CYCLES_BEFORE_EMU_TIMER + remaining_cycles);
		
		/* check the "local" joystick and buttons */
		if (!process_input())
			break;
		
		if ((tmp_tick = *rb->current_tick) >= time_to_display)
		{
			time_to_display += LOCAL_TICKS_BEFORE_LOCAL_REDRAW;
			
			/* prepare "current Vectrex FPS" display string */
			rb->snprintf(fps_display_buffer, sizeof(fps_display_buffer), "V:%02ld", current_vectrex_fps);
			rb->lcd_putsxy(0, 0, fps_display_buffer);
			
			/* prepare "current Local FPS" display string */
			rb->snprintf(fps_display_buffer, sizeof(fps_display_buffer), "L:%02ld", current_local_fps);
			rb->lcd_putsxy(0, LCD_HEIGHT-8, fps_display_buffer);
			
			/* redraw the *local* screen */
			rb->lcd_update();
			
			/* keep FPS */
			local_fps++;
			if ((tmp_tick = *rb->current_tick) >= next_local_fps_update)
			{
				current_local_fps = local_fps;
				next_local_fps_update = tmp_tick + HZ;
				local_fps = 0;
			}
		}
	}
}

int process_input()
{
	long button, lastbutton = BUTTON_NONE; /* button pressed */
	 
	/*button = rb->button_get(false)&(~BUTTON_REPEAT);*/ /* false = non-blocking */
	rb->button_clear_queue(); button = rb->button_status();
	switch(button)
	{
		case VK_QUIT: /* play : keypad + */
			return 0;
		
		case VK_1: /* stop : keypad Enter */
			snd_regs[14] &= ~0x01; /* bouton 1 */
			break;
		
		case VK_2: /* play : keypad + */
			snd_regs[14] &= ~0x02; /* bouton 2 */
			break;
		
		case VK_3: /* rec : keypad / (space?) */
			snd_regs[14] &= ~0x04; /* bouton 3 */
			break;
		
		case VK_4: /* A/B : keypad . (Ins) */
			snd_regs[14] &= ~0x08; /* bouton 4 */
			break;
			
		case VK_UP:
			alg_jch1 = 0xff;
			break;
		
		case VK_DOWN:
			alg_jch1 = 0x00;
			break;
		
		case VK_LEFT:
			alg_jch0 = 0x00;
			break;
		
		case VK_RIGHT:
			alg_jch0 = 0xff;
			break;
		
		default:
			snd_regs[14] |= 0x01; /* button 1 released */
			snd_regs[14] |= 0x02; /* button 2 released */
			snd_regs[14] |= 0x04; /* button 3 released */
			snd_regs[14] |= 0x08; /* button 4 released */
			alg_jch0 = 0x80; /* center joystick */
			alg_jch1 = 0x80; /* center joystick */
			
			/*if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
			{*/
/* useless test in this plugin */
/* #ifdef HAVE_LCD_CHARCELLS 
		pgfx_release();*/
/* #endif */
		/* return PLUGIN_USB_CONNECTED;
			}*/
			break;
	}
	
	if (button!=BUTTON_NONE)
		lastbutton = button;
	
	return 1;
}

#endif /* #ifdef HAVE_LCD_BITMAP */
