summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/video/hd66421.cpp
blob: 449c1abc8d25e7d0a3d7d3361caf768ef3440612 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
                       
                                     










                                         
 



                                                                            

                                          





                            
 
                                                                                                  













































                                                                                   
                                                                                        


                      

                                              

                                                    
 





                                                   
                                                                                        
 
                                    

                                                  










                                                                            
                                                       
 
                                          






                                                   
                                                                   
 
                                          










                                                                            
                                                                                                               

                                                       
                                                                                                                               



                                     
 
                                
                         















                                                   
                                   
 
                                             


                     
                                            
 
                                                          


                     
                                   
 
                                             


                            
                                            
 
                                                          













                                     
                                   
                                                                 





                                                      
                                               




                                        
                                          





                                        
                                                                                   
 
                                           

 
                                                                                                              


                     
                                                        










                                                                                          
                                       
                                                                                           
     
                                                            
      






                                      
                               






                                                                                
                                       







                                          
                                                            
                                                          
         
 
                 
 
 
                                                                   



                                   
                                                         
                                        
                                                                 




         
                                                   
                                                 

                                                   



                                                                             
// license:BSD-3-Clause
// copyright-holders:Tim Schuerewegen
/*

    Hitachi HD66421 LCD Controller/Driver

    (c) 2001-2007 Tim Schuerewegen

*/

#include "emu.h"
#include "hd66421.h"


//**************************************************************************
//  MACROS / CONSTANTS
//**************************************************************************

//#define HD66421_BRIGHTNESS_DOES_NOT_WORK

#define LOG_LEVEL0 (1U << 1)
#define LOG_LEVEL1 (1U << 2)
#define LOG_LEVEL2 (1U << 3)

#define VERBOSE (LOG_LEVEL0)
#include "logmacro.h"

#define HD66421_RAM_SIZE  (hd66421_device::WIDTH * hd66421_device::HEIGHT / 4) // 2-bits per pixel

// R0 - control register 1
#define LCD_R0_RMW      0x80 // read-modify-write mode
#define LCD_R0_DISP     0x40 // display on/off
#define LCD_R0_STBY     0x20 // standby (internal operation and power circuit halt)
#define LCD_R0_PWR      0x10
#define LCD_R0_AMP      0x08
#define LCD_R0_REV      0x04 // reverse
#define LCD_R0_HOLT     0x02
#define LCD_R0_ADC      0x01

// R1 - control register 2
#define LCD_R1_BIS1     0x80 // bias ratio (bit 1)
#define LCD_R1_BIS0     0x40 // bias ratio (bit 0)
#define LCD_R1_WLS      0x20
#define LCD_R1_GRAY     0x10 // grayscale palette 4/32
#define LCD_R1_DTY1     0x08 // display duty cycle (bit 1)
#define LCD_R1_DTY0     0x04 // display duty cycle (bit 0)
#define LCD_R1_INC      0x02
#define LCD_R1_BLK      0x01 // blink function

// register 0 to 16
#define LCD_REG_CONTROL_1   0x00 // control register 1
#define LCD_REG_CONTROL_2   0x01 // control register 2
#define LCD_REG_ADDR_X      0x02 // x address register
#define LCD_REG_ADDR_Y      0x03 // y address register
#define LCD_REG_RAM         0x04 // display ram access register
#define LCD_REG_START_Y     0x05 // display start line register
#define LCD_REG_BLINK_START 0x06 // blink start line register
#define LCD_REG_BLINK_END   0x07 // blink end line register
#define LCD_REG_BLINK_1     0x08 // blink register 1
#define LCD_REG_BLINK_2     0x09 // blink register 2
#define LCD_REG_BLINK_3     0x0A // blink register 3
#define LCD_REG_PARTIAL     0x0B // partial display block register
#define LCD_REG_COLOR_1     0x0C // gray scale palette 1 (0,0)
#define LCD_REG_COLOR_2     0x0D // gray scale palette 2 (0,1)
#define LCD_REG_COLOR_3     0x0E // gray scale palette 3 (1,0)
#define LCD_REG_COLOR_4     0x0F // gray scale palette 4 (1,1)
#define LCD_REG_CONTRAST    0x10 // contrast control register
#define LCD_REG_PLANE       0x11 // plane selection register

//**************************************************************************
//  GLOBAL VARIABLES
//**************************************************************************

// devices
DEFINE_DEVICE_TYPE(HD66421, hd66421_device, "hd66421", "Hitachi HD66421 LCD Controller")


// default address map
void hd66421_device::hd66421(address_map &map)
{
	if (!has_configured_map(0))
		map(0x0000, HD66421_RAM_SIZE).ram();
}

//-------------------------------------------------
//  memory_space_config - return a description of
//  any address spaces owned by this device
//-------------------------------------------------

device_memory_interface::space_config_vector hd66421_device::memory_space_config() const
{
	return space_config_vector {
		std::make_pair(0, &m_space_config)
	};
}


//**************************************************************************
//  INLINE HELPERS
//**************************************************************************

//-------------------------------------------------
//  readbyte - read a byte at the given address
//-------------------------------------------------

inline uint8_t hd66421_device::readbyte(offs_t address)
{
	return space().read_byte(address);
}


//-------------------------------------------------
//  writebyte - write a byte at the given address
//-------------------------------------------------

inline void hd66421_device::writebyte(offs_t address, uint8_t data)
{
	space().write_byte(address, data);
}


//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  hd66421_device - constructor
//-------------------------------------------------

hd66421_device::hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, HD66421, tag, owner, clock)
	, device_memory_interface(mconfig, *this)
	, m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, address_map_constructor(FUNC(hd66421_device::hd66421), this))
	, m_cmd(0)
	, m_x(0)
	, m_y(0)
	, m_palette(*this, "palette")
{
	for (auto &elem : m_reg)
		elem = 0;
}


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

void hd66421_device::device_start()
{
	// register for state saving
	save_item(NAME(m_cmd));
	save_item(NAME(m_reg));
	save_item(NAME(m_x));
	save_item(NAME(m_y));
}

uint8_t hd66421_device::reg_idx_r()
{
	LOGMASKED(LOG_LEVEL2, "reg_idx_r\n");
	return m_cmd;
}

void hd66421_device::reg_idx_w(uint8_t data)
{
	LOGMASKED(LOG_LEVEL2, "reg_idx_w (%02X)\n", data);
	m_cmd = data;
}

uint8_t hd66421_device::reg_dat_r()
{
	LOGMASKED(LOG_LEVEL2, "reg_dat_r\n");
	return m_reg[m_cmd];
}

void hd66421_device::reg_dat_w(uint8_t data)
{
	LOGMASKED(LOG_LEVEL2, "reg_dat_w (%02X)\n", data);
	m_reg[m_cmd] = data;

	switch (m_cmd)
	{
		case LCD_REG_ADDR_X :
			m_x = data;
			break;

		case LCD_REG_ADDR_Y :
			m_y = data;
			break;

		case LCD_REG_RAM :
		{
			uint8_t r1;
			writebyte(m_y * (WIDTH / 4) + m_x, data);
			r1 = m_reg[LCD_REG_CONTROL_2];
			if (r1 & 0x02)
				m_x++;
			else
				m_y++;

			if (m_x >= (WIDTH / 4))
			{
				m_x = 0;
				m_y++;
			}

			if (m_y >= HEIGHT)
				m_y = 0;
		}
		break;
	}
}

void hd66421_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color)
{
	bitmap.pix(y, x) = (uint16_t)color;
}

uint32_t hd66421_device::update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	pen_t pen[4];

	LOGMASKED(LOG_LEVEL1, "video_update_hd66421\n");

	// update palette
	for (int i = 0; i < 4; i++)
	{
		double bright;
		int temp;
		temp = 31 - (m_reg[LCD_REG_COLOR_1 + i] - m_reg[LCD_REG_CONTRAST] + 0x03);
		if (temp <  0) temp =  0;
		if (temp > 31) temp = 31;
		bright = 1.0 * temp / 31;
		pen[i] = i;
#ifdef HD66421_BRIGHTNESS_DOES_NOT_WORK
		m_palette->set_pen_color(pen[i], 255 * bright, 255 * bright, 255 * bright);
#else
		m_palette->set_pen_contrast(pen[i], bright);
#endif
	}

	// draw bitmap (bottom to top)
	if (m_reg[0] & LCD_R0_DISP)
	{
		int x, y;
		x = 0;
		y = HEIGHT - 1;

		for (int i = 0; i < HD66421_RAM_SIZE; i++)
		{
			plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 6) & 3]);
			plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 4) & 3]);
			plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 2) & 3]);
			plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 0) & 3]);
			if (x >= WIDTH)
			{
				x = 0;
				y = y - 1;
			}
		}
	}
	else
	{
		rectangle rect(0, WIDTH - 1, 0, HEIGHT - 1);
		bitmap.fill(m_palette->white_pen(), rect);
	}

	return 0;
}

void hd66421_device::hd66421_palette(palette_device &palette) const
{
	// init palette
	for (int i = 0; i < 4; i++)
	{
		palette.set_pen_color(i, rgb_t::white());
#ifndef HD66421_BRIGHTNESS_DOES_NOT_WORK
		palette.set_pen_contrast(i, double(i) / (4 - 1));
#endif
	}
}


//-------------------------------------------------
//  device_add_mconfig - add device configuration
//-------------------------------------------------

void hd66421_device::device_add_mconfig(machine_config &config)
{
	PALETTE(config, m_palette, FUNC(hd66421_device::hd66421_palette), 4);
}