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

    DEC VT Terminal video emulation
    [ DC012 and DC011 emulation ]

    01/05/2009 Initial implementation [Miodrag Milanovic]
    xx/xx/2013 portions by Karl-Ludwig Deisenhofer.

    DEC VIDEO : STATE AS OF NOVEMBER 2013
    -------------------------------------
    - NOT FULLY WORKING : scrolling requires implementation of 'scrolling region'. Multiple regions could be present.
                          Split & full screen modes exist. Scroll should be synced with beam or DMA.
                          See 4.7.4 and up in VT manual.

    - TESTS REQUIRED : do line and character attributes (plus combinations) match real hardware?

    - UNDOCUMENTED FEATURES of DC011 / DC012 (CLUES WANTED)
       A. (VT 100): DEC VT terminals are said to have a feature that doubles the number of lines
                    (50 real lines or just interlaced mode with 500 instead of 250 scanlines?)

       B. (DEC-100-B) fun PD program SQUEEZE.COM _compresses_ display to X/2 and Y/2
          - so picture takes a quarter of the original screen. How does it accomplish this?

    - IMPROVEMENTS:
        - exact colors for different VR201 monitors ('paper white', green and amber)

    Copyright MESS Team.
    Visit http://mamedev.org for licensing and usage restrictions.

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

#include "emu.h"
#include "video/vtvideo.h"

/***************************************************************************
    PARAMETERS
***************************************************************************/

#define VERBOSE         0

#define LOG(x)      do { if (VERBOSE) logerror x; } while (0)


const device_type VT100_VIDEO = &device_creator<vt100_video_device>;
const device_type RAINBOW_VIDEO = &device_creator<rainbow_video_device>;


vt100_video_device::vt100_video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
					: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
						device_video_interface(mconfig, *this)
{
}


vt100_video_device::vt100_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: device_t(mconfig, VT100_VIDEO, "VT100 Video", tag, owner, clock, "vt100_video", __FILE__),
						device_video_interface(mconfig, *this)
{
}


rainbow_video_device::rainbow_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: vt100_video_device(mconfig, RAINBOW_VIDEO, "Rainbow Video", tag, owner, clock, "rainbow_video", __FILE__)
{
}


//-------------------------------------------------
//  device_config_complete - perform any
//  operations now that the configuration is
//  complete
//-------------------------------------------------

void vt100_video_device::device_config_complete()
{
	// inherit a copy of the static data
	const vt_video_interface *intf = reinterpret_cast<const vt_video_interface *>(static_config());
	if (intf != NULL)
		*static_cast<vt_video_interface *>(this) = *intf;

	// or initialize to defaults if none provided
	else
	{
		memset(&m_in_ram_cb, 0, sizeof(m_in_ram_cb));
		memset(&m_clear_video_cb, 0, sizeof(m_clear_video_cb));
		m_char_rom_tag = "";
	}
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void vt100_video_device::device_start()
{
	/* resolve callbacks */
	m_in_ram_func.resolve(m_in_ram_cb, *this);
	m_clear_video_interrupt.resolve(m_clear_video_cb, *this);

	m_gfx = machine().root_device().memregion(m_char_rom_tag)->base();
	assert(m_gfx != NULL);

	// LBA7 is scan line frequency update
	machine().scheduler().timer_pulse(attotime::from_nsec(31778), timer_expired_delegate(FUNC(vt100_video_device::lba7_change),this));

	save_item(NAME(m_lba7));
	save_item(NAME(m_scroll_latch));
	save_item(NAME(m_blink_flip_flop));
	save_item(NAME(m_reverse_field));
	save_item(NAME(m_basic_attribute));
	save_item(NAME(m_columns));
	save_item(NAME(m_height));
	save_item(NAME(m_height_MAX));
	save_item(NAME(m_skip_lines));
	save_item(NAME(m_frequency));
	save_item(NAME(m_interlaced));
}

//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void vt100_video_device::device_reset()
{
	palette_set_color_rgb(machine(), 0, 0x00, 0x00, 0x00); // black
	palette_set_color_rgb(machine(), 1, 0xff, 0xff, 0xff); // white

	m_height = 25;
	m_height_MAX = 25;

	m_lba7 = 0;

	m_scroll_latch = 0;
	m_blink_flip_flop = 0;
	m_reverse_field = 0;
	m_basic_attribute = 0;

	m_columns = 80;
	m_frequency = 60;
	m_interlaced = 1;
	m_skip_lines = 2; // for 60Hz
}

// ****** RAINBOW ******
// 4 color (= monochrome intensities) palette, 24 and 48 line modes.
void rainbow_video_device::device_reset()
{
	MHFU_FLAG = false;
	MHFU_counter = 0; // **** MHFU: OFF ON COLD BOOT ! ****

	// (rest of the palette is set in the main program)
	palette_set_color_rgb(machine(), 0, 0x00, 0x00, 0x00); // black

	m_height = 24;  // <---- DEC-100
	m_height_MAX = 48;

	m_lba7 = 0;

	m_scroll_latch = 0;
	m_blink_flip_flop = 0;
	m_reverse_field = 0;
	m_basic_attribute = 0;

	m_columns = 80;
	m_frequency = 60;
	m_interlaced = 1;
	m_skip_lines = 2; // for 60Hz
}

/***************************************************************************
    IMPLEMENTATION
***************************************************************************/

// Also used by Rainbow-100 ************
void vt100_video_device::recompute_parameters()
{
	int horiz_pix_total = 0;
	int vert_pix_total = 0;
	rectangle visarea;

	vert_pix_total  = m_height  * 10;

	if (m_columns == 132) {
		horiz_pix_total = m_columns * 9; // display 1 less filler pixel in 132 char. mode (DEC-100)
	} else {
		horiz_pix_total = m_columns * 10; // normal 80 character mode.
	}

	visarea.set(0, horiz_pix_total - 1, 0, vert_pix_total - 1);

	m_screen->configure(horiz_pix_total, vert_pix_total, visarea, m_screen->frame_period().attoseconds);
}


READ8_MEMBER( vt100_video_device::lba7_r )
{
	return m_lba7;
}


// Also used by Rainbow-100 ************
WRITE8_MEMBER( vt100_video_device::dc012_w )
{
	// TODO: writes to 10C/0C should be treated differently (emulation disables the watchdog too often).
	if (data == 0) // MHFU is disabled by writing 00 to port 010C.
	{
				//if (MHFU_FLAG == true)
				//  printf("MHFU  *** DISABLED *** \n");
				MHFU_FLAG = false;
				MHFU_counter = 0;
	}
	else
	{           // RESET
				//if (MHFU_FLAG == false)
				//  printf("MHFU  ___ENABLED___ \n");
				MHFU_FLAG = true;

				MHFU_counter = 0;
	}

	if (!(data & 0x08))
	{
		// The scroll offset put in 'm_scroll_latch' is a decimal offset controlling 10 scan lines.
		// The BIOS first writes the least significant bits, then the 2 most significant bits.

		// If scrolling up (incrementing the scroll latch), the additional line is linked in at the bottom.
		// When the scroll latch is incremented back to 0, the top line of the scrolling region must be unlinked.

		// When scrolling down (decrementing the scroll latch), new lines must be linked in at the top of the scroll region
		// and unlinked down at the bottom.

		// Note that the scroll latch value will be used during the next frame rather than the current frame.
		// All line linking/unlinking is done during the vertical blanking interval (< 550ms).

		// More on scrolling regions: Rainbow 100 B technical documentation (QV069-GZ) April 1985 page 22
		// Also see VT100 Technical Manual: 4.7.4 Address Shuffling to 4.7.9 Split Screen Smooth Scrolling.
		if (!(data & 0x04))
		{
			// set lower part scroll
			m_scroll_latch = (m_scroll_latch & 0x0c) | (data & 0x03);
		}
		else
		{
			// set higher part scroll
			m_scroll_latch = (m_scroll_latch & 0x03) | ((data & 0x03) << 2);
		}
	}
	else
	{
		switch (data & 0x0f)
		{
			case 0x08:
				// toggle blink flip flop
				m_blink_flip_flop = !(m_blink_flip_flop) ? 1 : 0;
				break;
			case 0x09:
				// clear vertical frequency interrupt;
				m_clear_video_interrupt(0, 0);

				break;
			case 0x0a:
				// set reverse field on
				m_reverse_field = 1;
				break;
			case 0x0b:
				// set reverse field off
				m_reverse_field = 0;
				break;

			//  Writing a 11XX bit combination clears the blink-flip flop (valid for 0x0C - 0x0F):
			case 0x0c:
				// set basic attribute to underline / blink flip-flop off
				m_blink_flip_flop = 0;
				m_basic_attribute = 0; // (VT-100 without AVO): reverse video is interpreted as underline (basic_attribute 0)
				break;

			case 0x0d:
				// (DEC Rainbow 100 DEFAULT) : reverse video with 24 lines / blink flip-flop off
				m_blink_flip_flop = 0;
				m_basic_attribute = 1; // (VT-100 without AVO): reverse video is interpreted as reverse (basic_attribute 1)

				if (m_height_MAX == 25) break; //  Abort on VT-100 for now.

				if (m_height != 24)
				{
					m_height = 24;  // (DEC Rainbow 100) : 24 line display
					recompute_parameters();
				}
				break;

			case 0x0e:
				m_blink_flip_flop = 0;  // 'unsupported' DC012 command. Turn blink flip-flop off.
				break;

			case 0x0f:
				// (DEC Rainbow 100): reverse video with 48 lines / blink flip-flop off
				m_blink_flip_flop = 0;
				m_basic_attribute = 1;

				// 0x0f = 'reserved' on VT 100
				//  Abort on VT-100 for now.
				if (m_height_MAX == 25) break;

				if (m_height != 48)
				{
					m_height = 48;   // (DEC Rainbow 100) : 48 line display
					recompute_parameters();
				}
				break;
		}
	}
}


WRITE8_MEMBER( vt100_video_device::dc011_w )
{
	if (!BIT(data, 5))
	{
		UINT8 col = m_columns;
		if (!BIT(data, 4))
		{
			m_columns = 80;
		}
		else
		{
			m_columns = 132;
		}
		if (col != m_columns)
		{
			recompute_parameters();
		}
		m_interlaced = 1;
	}
	else
	{
		if (!BIT(data, 4))
		{
			m_frequency = 60;
			m_skip_lines = 2;
		}
		else
		{
			m_frequency = 50;
			m_skip_lines = 5;
		}
		m_interlaced = 0;
	}
}

WRITE8_MEMBER( vt100_video_device::brightness_w )
{
	//palette_set_color_rgb(machine(), 1, data, data, data);
}



void vt100_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x, int y, UINT8 scroll_region, UINT8 display_type)
{
	UINT8 line = 0;
	int bit = 0, prevbit, invert = 0, j;
	int double_width = (display_type == 2) ? 1 : 0;

	for (int i = 0; i < 10; i++)
	{
		switch (display_type)
		{
			case 0 : // bottom half, double height
						j = (i >> 1) + 5; break;
			case 1 : // top half, double height
						j = (i >> 1); break;
			case 2 : // double width
			case 3 : // normal
						j = i;  break;
			default : j = 0; break;
		}
		// modify line since that is how it is stored in rom
		if (j == 0) j = 15; else j = j - 1;

		line = m_gfx[(code & 0x7f) * 16 + j];

		if (m_basic_attribute == 1)
		{
			if ((code & 0x80) == 0x80)
				invert = 1;
			else
				invert = 0;
		}

		for (int b = 0; b < 8; b++)
		{
			prevbit = bit;
			bit = BIT((line << b), 7);
			if (double_width)
			{
				bitmap.pix16(y * 10 + i, x * 20 + b * 2)     =  (bit | prevbit) ^ invert;
				bitmap.pix16(y * 10 + i, x * 20 + b * 2 + 1) =  bit ^ invert;
			}
			else
			{
				bitmap.pix16(y * 10 + i, x * 10 + b) =  (bit | prevbit) ^ invert;
			}
		}
		prevbit = bit;
		// char interleave is filled with last bit
		if (double_width)
		{
			bitmap.pix16(y * 10 + i, x * 20 + 16) =  (bit | prevbit) ^ invert;
			bitmap.pix16(y * 10 + i, x * 20 + 17) =  bit ^ invert;
			bitmap.pix16(y * 10 + i, x * 20 + 18) =  bit ^ invert;
			bitmap.pix16(y * 10 + i, x * 20 + 19) =  bit ^ invert;
		}
		else
		{
			bitmap.pix16(y * 10 + i, x * 10 + 8) =  (bit | prevbit) ^ invert;
			bitmap.pix16(y * 10 + i, x * 10 + 9) =  bit ^ invert;
		}
	}
}

void vt100_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	UINT16 addr = 0;
	int line = 0;
	int xpos = 0;
	int ypos = 0;
	UINT8 code;
	int x = 0;
	UINT8 scroll_region = 1; // binary 1
	UINT8 display_type = 3;  // binary 11
	UINT16 temp = 0;

	if (m_in_ram_func(0) != 0x7f)
		return;

	while (line < (m_height + m_skip_lines))
	{
		code = m_in_ram_func(addr + xpos);
		if (code == 0x7f)
		{
			// end of line, fill empty till end of line
			if (line >= m_skip_lines)
			{
				for (x = xpos; x < ((display_type == 2) ? (m_columns / 2) : m_columns); x++)
				{
					display_char(bitmap, code, x, ypos, scroll_region, display_type);
				}
			}
			// move to new data
			temp = m_in_ram_func(addr + xpos + 1) * 256 + m_in_ram_func(addr + xpos + 2);
			addr = (temp) & 0x1fff;
			// if A12 is 1 then it is 0x2000 block, if 0 then 0x4000 (AVO)
			if (addr & 0x1000) addr &= 0xfff; else addr |= 0x2000;
			scroll_region = (temp >> 15) & 1;
			display_type  = (temp >> 13) & 3;
			if (line >= m_skip_lines)
			{
				ypos++;
			}
			xpos = 0;
			line++;
		}
		else
		{
			// display regular char
			if (line >= m_skip_lines)
			{
				display_char(bitmap, code, xpos, ypos, scroll_region, display_type);
			}
			xpos++;
			if (xpos > m_columns)
			{
				line++;
				xpos = 0;
			}
		}
	}

}

// ****** RAINBOW ******
// 5 possible CHARACTER STATES (normal, reverse, bold, blink, underline) are encoded into display_type.

// From the VT-180 specs, chapter 6-43 (where multiple attributes are described):
//  1) reverse characters [ XOR of reverse video and reverse screen (A) ] normally have dim backgrounds with black characters (B)
//  2) bold and reverse together give a background of normal intensity

//  3) blink controls intensity: normal chars vary between A) normal and dim  (B) bold chars vary between bright and normal
//  4) blink applied to a
//       A) reverse character causes it to alternate between normal and reverse video representation
//       B) non-rev. "        : alternate between usual intensity and the next lower intensity
//  5) underline causes the 9.th scan to be forced to
//       A) white of the same intensity as the characters (for nonreversed characters),
//       b) to black (for reverse characters)

// LINE ATTRIBUTE 'double_height' always is interpreted as 'double width + double height'
void rainbow_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x, int y, UINT8 scroll_region, UINT8 display_type)
{
	UINT16 y_preset;
	UINT16 x_preset, d_x_preset;
	if (m_columns == 132)
	{     x_preset   = x * 9;
			d_x_preset = x * 18;
	} else
	{
			x_preset   = x * 10;
			d_x_preset = x * 20;
	}

	UINT8 line = 0;
	int bit = 0, j = 0;
	int fg_intensity;
	int back_intensity, back_default_intensity;

	int invert = (display_type &  8) >> 3; // BIT 3 indicates REVERSE
	int bold = (display_type & 16) >> 4;   // BIT 4 indicates BOLD
	int blink  = display_type &  32;       // BIT 5 indicates BLINK
	int underline = display_type & 64;     // BIT 6 indicates UNDERLINE
	bool blank = (display_type & 0x80) ? true : false; // BIT 7 indicates BLANK

	display_type = display_type & 3;

	// CASE 1 A)
	// SCREEN ATTRIBUTES (see VT-180 manual 6-30):
	// 'reverse field' = reverse video over entire screen (identical on Rainbow-100)

	// What does 'base attribute' do on Rainbow-100 ?
	// VT-100 interpretation ('without AVO, eigth char.bit defines base attribute') most likely not correct!
	// OR 'base attribute' = reverse or underline (depending on the selection of the cursor at SETUP) ??
	// VT-100 manual 4-75 / 4-98 says: reverse = (reverse field H) XOR (reverse video H = base attribute input)

	// For reference: a complete truth table can be taken from TABLE 4-6-4 / VT100 technical manual.
	// Following simple IF statements implement it in full. Code should not be shuffled!
	invert = invert ^ m_reverse_field ^ m_basic_attribute;

	fg_intensity = bold + 2;   // FOREGROUND (FG):  normal (2) or bright (3)

	back_intensity = 0; // DO NOT SHUFFLE CODE AROUND !!
	if ( (blink != 0) && ( m_blink_flip_flop != 0 ) )
		fg_intensity -= 1; // normal => dim    bright => normal (when bold)

	// INVERSION: background gets foreground intensity (reduced by 1).
	// _RELIES ON_ on_ previous evaluation of the BLINK signal (fg_intensity).
	if (invert != 0)
	{
		back_intensity = fg_intensity - 1; // BG: normal => dim;  dim => OFF;   bright => normal

		if (back_intensity != 0)           //  FG: avoid 'black on black'
			fg_intensity = 0;
		else
			fg_intensity = fg_intensity + 1; // FG: dim => normal; normal => bright
	}

	// BG: DEFAULT for entire character (underline overrides this for 1 line) -
	back_default_intensity = back_intensity;

	bool double_width  = (display_type != 3) ? true  : false; // all except normal: double width
	bool double_height = (display_type &  1) ? false : true;  // 0,2 = double height

	for (int i = 0; i < 10; i++)
	{
		y_preset = y * 10 + i;

		switch (display_type)
		{
			case 0 :  // bottom half of 'double height, double width' char.
						j = (i >> 1) + 5;
						break;

			case 2 :  // top half of 'double height, double width' char.
						j = (i >> 1);
						break;

			default : // 1: double width
						// 3: normal
						j = i;
						break;
		}

		// modify line since that is how it is stored in rom
		if (j == 0) j = 15; else j = j - 1;

		line = m_gfx[ (code << 4) + j]; // code * 16

		// UNDERLINED CHARACTERS (CASE 5 - different in 1 line):
		back_intensity = back_default_intensity; // 0, 1, 2
		if ( underline != 0 )
		{
			if ( i == 8 )
			{
					if (invert == 0)
						line = 0xff; // CASE 5 A)
					else
					{    line = 0x00; // CASE 5 B)
						back_intensity = 0; // OVERRIDE: BLACK BACKGROUND
					}
			}
		}

		for (int b = 0; b < 8; b++) // 0..7
		{
			if (blank)
			{       bit = m_reverse_field ^ m_basic_attribute;
			}
			else
			{
					bit = BIT((line << b), 7);

					if (bit > 0)
						bit = fg_intensity;
					else
						bit = back_intensity;
			}

			// Double, 'double_height + double_width', then normal.
			if (double_width)
			{
				bitmap.pix16( y_preset, d_x_preset + (b << 1) + 1) = bit;
				bitmap.pix16( y_preset, d_x_preset + (b << 1)    ) = bit;

				if (double_height)
				{
						bitmap.pix16( 1 + y_preset, d_x_preset + (b << 1) + 1) = bit;
						bitmap.pix16( 1 + y_preset, d_x_preset + (b << 1)    ) = bit;
				}
			}
			else
			{
				bitmap.pix16(y_preset, x_preset + b) = bit;
			}
		} // for (8 bit)


		// char interleave (X) is filled with last bit
		if (double_width)
		{
			// double chars: 18 or 20 bits
			bitmap.pix16(y_preset, d_x_preset + 16) = bit;
			bitmap.pix16(y_preset, d_x_preset + 17) = bit;

			if (m_columns == 80)
			{   bitmap.pix16(y_preset, d_x_preset + 18) = bit;
				bitmap.pix16(y_preset, d_x_preset + 19) = bit;
			}
		}
		else
		{   // normal chars: 9 or 10 bits
			bitmap.pix16(y_preset, x_preset + 8) = bit;

			if (m_columns == 80)
				bitmap.pix16(y_preset, x_preset + 9) = bit;
		}

	} // for

}

// ****** RAINBOW ******
void rainbow_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	UINT16 addr = 0;
	UINT16 attr_addr = 0;
	int line = 0;
	int xpos = 0;
	int ypos = 0;
	UINT8 code;
	int x = 0;
	UINT8 scroll_region = 1;  // DEFAULT TO 1 = PART OF scroll_region
	UINT8 display_type = 3;  // binary 11
	UINT16 temp = 0;

	while (line < (m_height + m_skip_lines))
	{
		code = m_in_ram_func(addr + xpos);

		if ( code == 0x00 )        // TODO: investigate side effect on regular zero character!
				display_type |= 0x80; // DEFAULT: filler chars (till end of line) and empty lines (00) will be blanked
		else
				display_type &= 0x7f; // else activate display.

		if ( code == 0xff )
		{
			// end of line, fill empty till end of line
			if (line >= m_skip_lines)
			{
				// NOTE: display_type is already shifted! All except 3 is DOUBLE WIDTH 40 or 66 chars per line
				for (x = xpos; x < ( (display_type != 3) ? (m_columns / 2) : m_columns );  x++)
				{
					display_char(bitmap, code, x, ypos, scroll_region, display_type | 0x80);
				}

			}

			//  LINE ATTRIBUTE - valid for all chars on next line  ** DO NOT SHUFFLE **
			attr_addr = 0x1000 | ( (addr + xpos + 1) & 0x0fff );

			// MOVE TO NEW DATA
			temp = m_in_ram_func(addr + xpos + 2) * 256 + m_in_ram_func(addr + xpos + 1);
			addr = (temp) & 0x0fff;

			temp = m_in_ram_func(attr_addr);
			scroll_region = (temp) & 1;
			display_type  = (temp >> 1) & 3;

			if (line >= m_skip_lines)
			{
				ypos++;
			}
			xpos = 0;
			line++;
		}
		else
		{
			// display regular char
			if (line >= m_skip_lines)
			{
				attr_addr = 0x1000 | ( (addr + xpos) & 0x0fff );
				temp = m_in_ram_func(attr_addr); // get character attribute

				// CONFIRMED: Reverse active on 1.  No attributes = 0x0E
				// 1 = display char. in REVERSE   (encoded as 8)
				// 0 = display char. in BOLD      (encoded as 16)
				// 0 = display char. w. BLINK     (encoded as 32)
				// 0 = display char. w. UNDERLINE (encoded as 64).
				display_char(bitmap, code, xpos, ypos, scroll_region, display_type | (   (    (temp & 1)) << 3 )
																						| ( (2-(temp & 2)) << 3 )
																						| ( (4-(temp & 4)) << 3 )
																						| ( (8-(temp & 8)) << 3 )
																					);

			}
			xpos++;

			if (xpos > m_columns )
			{
				xpos = 0;
				line++;
			}
		} // (else) valid char

	} // while


}


void rainbow_video_device::palette_select ( int choice )
{
	switch(choice)
	{
			default:
			case 0x01:
						palette_set_color_rgb(machine(), 1, 0xff-100, 0xff-100, 0xff-100);  // WHITE (dim)
						palette_set_color_rgb(machine(), 2, 0xff-50, 0xff-50, 0xff-50);     // WHITE NORMAL
						palette_set_color_rgb(machine(), 3, 0xff, 0xff, 0xff);              // WHITE (brighter)
						break;

			case 0x02:
						palette_set_color_rgb(machine(), 1, 0 , 205 -50, 100 - 50);        // GREEN (dim)
						palette_set_color_rgb(machine(), 2, 0 , 205,     100     );        // GREEN (NORMAL)
						palette_set_color_rgb(machine(), 3, 0,  205 +50, 100 + 50);        // GREEN (brighter)
						break;

			case 0x03:
						palette_set_color_rgb(machine(), 1, 213 - 47, 146 - 47, 82 - 47); // AMBER (dim)
						palette_set_color_rgb(machine(), 2, 213,      146,      82     ); // AMBER (NORMAL)
						palette_set_color_rgb(machine(), 3, 255,      193,      129    ); // AMBER (brighter)
						break;
	}
}

// ****** RAINBOW ******
void rainbow_video_device::video_blanking(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	// 'In reverse screen mode, termination forces the beam to the screen background intensity'
	// Background intensity means 'dim' (1) according to one source.
	bitmap.fill( ((m_reverse_field ^ m_basic_attribute) ? 1 : 0) , cliprect);
}



int rainbow_video_device::MHFU(int ASK)
{
	switch (ASK)
	{
			case 1:         // "true": RETURN BOOLEAN (MHFU disabled or enabled?)
				return MHFU_FLAG;

			case -1:        // -1: increment, return counter value (=> Rainbow.c)
					if (MHFU_FLAG == true)
					MHFU_counter++;
				return MHFU_counter;

			case -100:          // -100 : RESET and ENABLE MHFU counter
				//printf("-100 MHFU  * reset and ENABLE * \n");
				MHFU_counter = 0;

				//if (MHFU_FLAG == false)
				//  printf("-100 MHFU  ___ENABLED___\n");
				MHFU_FLAG = true;

				return -100;

			default:
				assert(1);
				return -255;
	} // switch
}

TIMER_CALLBACK_MEMBER( vt100_video_device::lba7_change )
{
	m_lba7 = (m_lba7) ? 0 : 1;
}
