#include "driver.h"
#include "astrof.h"


#define MASTER_CLOCK  		(10595000)
#define MAIN_CPU_CLOCK  	(MASTER_CLOCK / 16)
#define PIXEL_CLOCK  		(MASTER_CLOCK / 2)
#define HTOTAL				(0x150)
#define HBEND				(0x000)
#define HBSTART				(0x100)
#define ASTROF_VTOTAL		(0x107)
#define ASTROF_VBEND		(0x008)
#define VBSTART				(0x100)


static UINT8 *astrof_videoram;
static size_t astrof_videoram_size;
static UINT8 *astrof_colorram;

static emu_timer *irq_timer;

static UINT8 *astrof_color;
static UINT8 astrof_palette_bank;
static UINT8 red_on;
static UINT8 flipscreen;
static UINT8 screen_off;


/*************************************
 *
 *  IRQ generation
 *
 *************************************/

static READ8_HANDLER( irq_ack_r )
{
	cpunum_set_input_line(0, 0, CLEAR_LINE);

	return 0;
}


static TIMER_CALLBACK( irq_callback )
{
	cpunum_set_input_line(0, 0, ASSERT_LINE);

	timer_adjust(irq_timer, video_screen_get_time_until_pos(0, VBSTART, 0), 0, attotime_zero);
}


static void create_irq_timer(void)
{
	irq_timer = timer_alloc(irq_callback, NULL);
}


static void start_irq_timer(void)
{
	timer_adjust(irq_timer, video_screen_get_time_until_pos(0, VBSTART, 0), 0, attotime_zero);
}



/*************************************
 *
 *  Machine setup
 *
 *************************************/

static MACHINE_START( astrof )
{
	/* register for state saving */
	state_save_register_global(astrof_palette_bank);

	machine_start_astrof_audio(machine);
	create_irq_timer();

	/* register for state saving */
	state_save_register_global(red_on);
	state_save_register_global(flipscreen);
	state_save_register_global(screen_off);
}


/*************************************
 *
 *  Machine reset
 *
 *************************************/

static MACHINE_RESET( astrof )
{
	start_irq_timer();
}


/*************************************
 *
 *  Input handling
 *
 *************************************/

static INTERRUPT_GEN( coin_nmi )
{
	UINT32 coin = readinputportbytag("COIN");
	UINT32 service = readinputportbytag("SERVICE");

	/* both the coin input and the serice credit generates an NMI */
	if (coin || service)
		cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);

	/* the coin input is also connected to the coin counter */
	if (coin)
	{
		coin_counter_w(0, 1);
		coin_counter_w(0, 0);
	}
}


static UINT32 astrof_p1_controls_r(void *param)
{
	return readinputportbytag("P1");
}


static UINT32 astrof_p2_controls_r(void *param)
{
	UINT32 ret;

	/* on an upright cabinets, a single set of controls
       is connected to both sets of pins on the edge
       connector */
	if (readinputportbytag("CAB"))
		ret = readinputportbytag("P2");
	else
		ret = readinputportbytag("P1");

	return ret;
}



/*************************************
 *
 *  Video system
 *
 *************************************/

#define ASTROF_NUM_PENS		(0x10)
#define TOMAHAWK_NUM_PENS	(0x20)


static VIDEO_START( astrof )
{
	/* allocate the color RAM -- half the size of the video RAM as A0 is not connected */
	astrof_colorram = auto_malloc(astrof_videoram_size / 2);
	state_save_register_global_pointer(astrof_colorram, astrof_videoram_size / 2);
}


static rgb_t make_pen(UINT8 data)
{
	UINT8 r1_bit = ((data >> 0) & 0x01) | red_on;
	UINT8 r2_bit = ((data >> 1) & 0x01) | red_on;
	UINT8 g1_bit = ( data >> 2) & 0x01;
	UINT8 g2_bit = ( data >> 3) & 0x01;
	UINT8 b1_bit = ( data >> 4) & 0x01;
	UINT8 b2_bit = ( data >> 5) & 0x01;

	/* this is probably not quite right, but I don't have the
       knowledge to figure out the actual weights - ZV */
	UINT8 r = (0xc0 * r1_bit) + (0x3f * r2_bit);
	UINT8 g = (0xc0 * g1_bit) + (0x3f * g2_bit);
	UINT8 b = (0xc0 * b1_bit) + (0x3f * b2_bit);

	return MAKE_RGB(r, g, b);
}


static void astrof_get_pens(pen_t *pens)
{
	offs_t i;

	for (i = 0; i < ASTROF_NUM_PENS; i++)
	{
		UINT8 data = memory_region(REGION_PROMS)[(astrof_palette_bank << 4) | i];

		pens[i] = make_pen(data);
	}
}


static WRITE8_HANDLER( astrof_videoram_w )
{
	astrof_videoram[offset] = data;
	astrof_colorram[offset >> 1] = *astrof_color & 0x0e;
}


static WRITE8_HANDLER( video_control_1_w )
{
	flipscreen = ((data >> 0) & 0x01) & readinputportbytag("FLIP");

	/* this ties to the CLR pin of the shift registers */
	screen_off = ((data >> 1) & 0x01);

	/* D2 - not connected in the schematics, but at one point Astro Fighter sets it to 1*/
	/* D3-D7 - not connected */

	video_screen_update_partial(0, video_screen_get_vpos(0));
}


static WRITE8_HANDLER( astrof_video_control_2_w )
{
	/* D0 - OUT0 - goes to edge conn. pin A10 - was perhaps meant to be a start lamp */
	/* D1 - OUT1 - goes to edge conn. pin A11 - was perhaps meant to be a start lamp */

	astrof_palette_bank = (data >> 2) & 0x01;

	red_on = (data >> 3) & 0x01;

	/* D4-D7 - not connected */

	video_screen_update_partial(0, video_screen_get_vpos(0));
}


static void video_update_common(mame_bitmap *bitmap, const rectangle *cliprect, pen_t *pens)
{
	offs_t offs;

	for (offs = 0; offs < astrof_videoram_size; offs++)
	{
		UINT8 data;
		int i;

		UINT8 color = astrof_colorram[offs >> 1];

		pen_t back_pen = pens[color | 0x00];
		pen_t fore_pen = pens[color | 0x01];

		UINT8 y = offs;
		UINT8 x = offs >> 8 << 3;

		if (!flipscreen)
			y = ~y;

		if ((y <= cliprect->min_y) || (y >= cliprect->max_y))
			continue;

		if (screen_off)
			data = 0;
		else
			data = astrof_videoram[offs];

		for (i = 0; i < 8; i++)
		{
			pen_t pen = (data & 0x01) ? fore_pen : back_pen;

			if (flipscreen)
				*BITMAP_ADDR32(bitmap, y, 255 - x) = pen;
			else
				*BITMAP_ADDR32(bitmap, y, x) = pen;

			x = x + 1;
			data = data >> 1;
		}
	}
}


static VIDEO_UPDATE( astrof )
{
	pen_t pens[ASTROF_NUM_PENS];

	astrof_get_pens(pens);

	video_update_common(bitmap, cliprect, pens);

	return 0;
}


/*************************************
 *
 *  Memory handlers
 *
 *************************************/

static ADDRESS_MAP_START( astrof_map, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x03ff) AM_MIRROR(0x1c00) AM_RAM
	AM_RANGE(0x2000, 0x3fff) AM_NOP
	AM_RANGE(0x4000, 0x5fff) AM_RAM AM_WRITE(astrof_videoram_w) AM_BASE(&astrof_videoram) AM_SIZE(&astrof_videoram_size)
	AM_RANGE(0x6000, 0x7fff) AM_NOP
	AM_RANGE(0x8000, 0x8002) AM_MIRROR(0x1ff8) AM_NOP
	AM_RANGE(0x8003, 0x8003) AM_MIRROR(0x1ff8) AM_READWRITE(MRA8_NOP, MWA8_RAM) AM_BASE(&astrof_color)
	AM_RANGE(0x8004, 0x8004) AM_MIRROR(0x1ff8) AM_READWRITE(MRA8_NOP, video_control_1_w)
	AM_RANGE(0x8005, 0x8005) AM_MIRROR(0x1ff8) AM_READWRITE(MRA8_NOP, astrof_video_control_2_w)
	AM_RANGE(0x8006, 0x8006) AM_MIRROR(0x1ff8) AM_READWRITE(MRA8_NOP, astrof_audio_1_w)
	AM_RANGE(0x8007, 0x8007) AM_MIRROR(0x1ff8) AM_READWRITE(MRA8_NOP, astrof_audio_2_w)
	AM_RANGE(0xa000, 0xa000) AM_MIRROR(0x1ff8) AM_READ_PORT("IN") AM_WRITE(MWA8_NOP)
	AM_RANGE(0xa001, 0xa001) AM_MIRROR(0x1ff8) AM_READ_PORT("DSW") AM_WRITE(MWA8_NOP)
	AM_RANGE(0xa002, 0xa002) AM_MIRROR(0x1ff8) AM_READWRITE(irq_ack_r, MWA8_NOP)
	AM_RANGE(0xa003, 0xa007) AM_MIRROR(0x1ff8) AM_NOP
	AM_RANGE(0xc000, 0xffff) AM_ROM
ADDRESS_MAP_END


/*************************************
 *
 *  Port definitions
 *
 *************************************/

static INPUT_PORTS_START( astrof )
	PORT_START_TAG("IN")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_START1 )
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START2 )
	PORT_BIT( 0x1c, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(astrof_p1_controls_r, 0)
	PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(astrof_p2_controls_r, 0)

	PORT_START_TAG("DSW")
	PORT_DIPNAME( 0x03, 0x00, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW:1,2")
	PORT_DIPSETTING(    0x00, "3" )
	PORT_DIPSETTING(    0x01, "4" )
	PORT_DIPSETTING(    0x02, "5" )
	PORT_DIPSETTING(    0x03, "6" )
	PORT_DIPNAME( 0x0c, 0x00, DEF_STR( Coinage ) ) PORT_DIPLOCATION("SW:3,4")
	PORT_DIPSETTING(    0x08, DEF_STR( 2C_1C ) )
  /*PORT_DIPSETTING(    0x0c, DEF_STR( 2C_1C ) )*/
	PORT_DIPSETTING(    0x00, DEF_STR( 1C_1C ) )
	PORT_DIPSETTING(    0x04, DEF_STR( 1C_2C ) )
	PORT_DIPNAME( 0x30, 0x00, DEF_STR( Bonus_Life ) ) PORT_DIPLOCATION("SW:5,6")
	PORT_DIPSETTING(    0x00, "3000" )
	PORT_DIPSETTING(    0x10, "5000" )
	PORT_DIPSETTING(    0x20, "7000" )
	PORT_DIPSETTING(    0x30, DEF_STR( None ) )
	PORT_DIPNAME( 0x40, 0x00, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW:7")
	PORT_DIPSETTING(    0x00, DEF_STR( Easy ) )
	PORT_DIPSETTING(    0x40, DEF_STR( Hard ) )
	PORT_BIT ( 0x80, IP_ACTIVE_LOW, IPT_VBLANK )

	PORT_START_TAG("P1")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_2WAY
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_2WAY
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 )
	PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED )

	PORT_START_TAG("P2")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_2WAY PORT_COCKTAIL
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_2WAY PORT_COCKTAIL
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_COCKTAIL
	PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED )

	PORT_START_TAG("COIN")
	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN1 ) PORT_IMPULSE(1)
	PORT_BIT( 0xfe, IP_ACTIVE_HIGH, IPT_UNUSED )

	PORT_START_TAG("SERVICE")
	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_SERVICE1 ) PORT_IMPULSE(1)
	PORT_BIT( 0xfe, IP_ACTIVE_HIGH, IPT_UNUSED )

	PORT_START_TAG("FLIP")
	PORT_DIPNAME( 0x01, 0x00, "Flip Screen for Player 2" ) PORT_DIPLOCATION("SW:8")
	PORT_DIPSETTING(    0x00, DEF_STR( Off ) )
	PORT_DIPSETTING(    0x01, DEF_STR( On ) )
	PORT_BIT( 0xfe, IP_ACTIVE_HIGH, IPT_UNUSED )

	PORT_START_TAG("CAB")
	PORT_CONFNAME( 0x01, 0x00, DEF_STR( Cabinet ) )
	PORT_CONFSETTING(    0x00, DEF_STR( Upright ) )
	PORT_CONFSETTING(    0x01, DEF_STR( Cocktail ) )
	PORT_BIT( 0xfe, IP_ACTIVE_HIGH, IPT_UNUSED )
INPUT_PORTS_END



/*************************************
 *
 *  Machine drivers
 *
 *************************************/

static MACHINE_DRIVER_START( base )

	/* basic machine hardware */
	MDRV_CPU_ADD_TAG("main", M6502, MAIN_CPU_CLOCK)
	MDRV_CPU_VBLANK_INT(coin_nmi,1)

	MDRV_MACHINE_RESET(astrof)

	/* video hardware */
	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
	MDRV_VIDEO_START(astrof)

	MDRV_SCREEN_ADD("main", 0)
	MDRV_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)

MACHINE_DRIVER_END


static MACHINE_DRIVER_START( astrof )

	/* basic machine hardware */
	MDRV_IMPORT_FROM(base)
	MDRV_CPU_MODIFY("main")
	MDRV_CPU_PROGRAM_MAP(astrof_map,0)

	MDRV_MACHINE_START(astrof)

	/* video hardware */
	MDRV_VIDEO_UPDATE(astrof)

	MDRV_SCREEN_MODIFY("main")
	MDRV_SCREEN_RAW_PARAMS(PIXEL_CLOCK, HTOTAL, HBEND, HBSTART, ASTROF_VTOTAL, ASTROF_VBEND, VBSTART)

	/* audio hardware */
	MDRV_IMPORT_FROM(astrof_audio)

MACHINE_DRIVER_END


/* Misfitmame start */

ROM_START( astrf_bl )
	ROM_REGION( 0x10000, REGION_CPU1, 0 )	/* 64k for code */
	ROM_LOAD( "afii.6",       0xd000, 0x0800, CRC(d6cd13a4) SHA1(359b00b02f4256f1138c8526214c6a34d2e5b47a) )
	ROM_LOAD( "afii.5",       0xd800, 0x0800, CRC(6fd3c4df) SHA1(73aad03e2588ac9f249d5751eb4a7c7cd12fd3b9) )
	ROM_LOAD( "afii.4",       0xe000, 0x0800, CRC(9612dae3) SHA1(8ee1797c212e06c381972b7b555f240ff317d75d) )
	ROM_LOAD( "afii.3",       0xe800, 0x0800, CRC(5a0fef42) SHA1(92a575abdf17bbb5ed6bc67479049523a985aa75) )
	ROM_LOAD( "afii.2",       0xf000, 0x0800, CRC(69f8a4fc) SHA1(9f9a935f19187640018009ade92f8993912ef6c2) )
	ROM_LOAD( "afii.1",       0xf800, 0x0800, CRC(322c09d2) SHA1(89723e3d998ff9cb9b174bca4b072b412b290c04) )

	ROM_REGION( 0x0020, REGION_PROMS, 0 )
	ROM_LOAD( "astrf_bl.clr", 0x0000, 0x0020, CRC(6be69d4b) SHA1(4197cf9110db08e45b5d18aedb0fde96779491c1) )
ROM_END


GAME( 1979, astrf_bl,  0,   astrof,   astrof,   0,  ROT90, "Hack",   "Astro Fighter (Black Background)", 0 )
/* Misfitmame end */
