diff options
Diffstat (limited to 'src/devices/video/hd44352.cpp')
-rw-r--r-- | src/devices/video/hd44352.cpp | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/src/devices/video/hd44352.cpp b/src/devices/video/hd44352.cpp new file mode 100644 index 00000000000..8b30b0afd9b --- /dev/null +++ b/src/devices/video/hd44352.cpp @@ -0,0 +1,439 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + Hitachi HD44352 LCD controller + +***************************************************************************/ + +#include "emu.h" +#include "video/hd44352.h" + +#define LCD_BYTE_INPUT 0x01 +#define LCD_BYTE_OUTPUT 0x02 +#define LCD_CHAR_OUTPUT 0x03 +#define LCD_ON_OFF 0x04 +#define LCD_CURSOR_GRAPHIC 0x06 +#define LCD_CURSOR_CHAR 0x07 +#define LCD_SCROLL_CHAR_WIDTH 0x08 +#define LCD_CURSOR_STATUS 0x09 +#define LCD_USER_CHARACTER 0x0b +#define LCD_CONTRAST 0x0c +#define LCD_IRQ_FREQUENCY 0x0d +#define LCD_CURSOR_POSITION 0x0e + + +// devices +const device_type HD44352 = &device_creator<hd44352_device>; + +//************************************************************************** +// live device +//************************************************************************** + +//------------------------------------------------- +// hd44352_device - constructor +//------------------------------------------------- + +hd44352_device::hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock): + device_t(mconfig, HD44352, "hd44352", tag, owner, clock, "hd44352", __FILE__), + m_on_cb(*this) +{ +} + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void hd44352_device::device_validity_check(validity_checker &valid) const +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd44352_device::device_start() +{ + m_on_cb.resolve_safe(); + + m_on_timer = timer_alloc(ON_TIMER); + m_on_timer->adjust(attotime::from_hz(m_clock/16384), 0, attotime::from_hz(m_clock/16384)); + + save_item( NAME(m_control_lines)); + save_item( NAME(m_data_bus)); + save_item( NAME(m_state)); + save_item( NAME(m_offset)); + save_item( NAME(m_char_width)); + save_item( NAME(m_bank)); + save_item( NAME(m_lcd_on)); + save_item( NAME(m_scroll)); + save_item( NAME(m_contrast)); + save_item( NAME(m_byte_count)); + save_item( NAME(m_cursor_status)); + save_item( NAME(m_cursor_x)); + save_item( NAME(m_cursor_y)); + save_item( NAME(m_cursor_lcd)); + save_item( NAME(m_video_ram[0])); + save_item( NAME(m_video_ram[1])); + save_item( NAME(m_par)); + save_item( NAME(m_cursor)); + save_item( NAME(m_custom_char[0])); + save_item( NAME(m_custom_char[1])); + save_item( NAME(m_custom_char[2])); + save_item( NAME(m_custom_char[3])); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hd44352_device::device_reset() +{ + memset(m_video_ram, 0x00, sizeof(m_video_ram)); + memset(m_par, 0x00, sizeof(m_par)); + memset(m_custom_char, 0x00, sizeof(m_custom_char)); + memset(m_cursor, 0x00, sizeof(m_cursor)); + m_control_lines = 0; + m_data_bus = 0xff; + m_state = 0; + m_bank = 0; + m_offset = 0; + m_char_width = 6; + m_lcd_on = 0; + m_scroll = 0; + m_byte_count = 0; + m_cursor_status = 0; + m_cursor_x = 0; + m_cursor_y = 0; + m_cursor_lcd = 0; + m_contrast = 0; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- +void hd44352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case ON_TIMER: + if (m_control_lines & 0x40) + { + m_on_cb(ASSERT_LINE); + m_on_cb(CLEAR_LINE); + } + break; + } +} + +//************************************************************************** +// device interface +//************************************************************************** + +UINT32 hd44352_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT8 cw = m_char_width; + + bitmap.fill(0, cliprect); + + if (m_control_lines&0x80 && m_lcd_on) + { + for (int a=0; a<2; a++) + for (int py=0; py<4; py++) + for (int px=0; px<16; px++) + if (BIT(m_cursor_status, 4) && px == m_cursor_x && py == m_cursor_y && a == m_cursor_lcd) + { + //draw the cursor + for (int c=0; c<cw; c++) + { + UINT8 d = compute_newval((m_cursor_status>>5) & 0x07, m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48], m_cursor[c]); + for (int b=0; b<8; b++) + { + bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b); + } + } + } + else + { + for (int c=0; c<cw; c++) + { + UINT8 d = m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48]; + for (int b=0; b<8; b++) + { + bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b); + } + } + } + } + + return 0; +} + + +void hd44352_device::control_write(UINT8 data) +{ + if(m_control_lines == data) + m_state = 0; + + m_control_lines = data; +} + +UINT8 hd44352_device::compute_newval(UINT8 type, UINT8 oldval, UINT8 newval) +{ + switch(type & 0x07) + { + case 0x00: + return (~oldval) & newval; + case 0x01: + return oldval ^ newval; + case 0x03: + return oldval & (~newval); + case 0x04: + return newval; + case 0x05: + return oldval | newval; + case 0x07: + return oldval; + case 0x02: + case 0x06: + default: + return 0; + } +} + +UINT8 hd44352_device::get_char(UINT16 pos) +{ + switch ((UINT8)pos/8) + { + case 0xcf: + return m_custom_char[0][pos%8]; + case 0xdf: + return m_custom_char[1][pos%8]; + case 0xef: + return m_custom_char[2][pos%8]; + case 0xff: + return m_custom_char[3][pos%8]; + default: + return region()->u8(pos); + } +} + +void hd44352_device::data_write(UINT8 data) +{ + // verify that controller is active + if (!(m_control_lines&0x80)) + return; + + if (m_control_lines & 0x01) + { + if (!(m_control_lines&0x02) && !(m_control_lines&0x04)) + return; + + switch (m_state) + { + case 0: //parameter 0 + m_par[m_state++] = data; + break; + case 1: //parameter 1 + m_par[m_state++] = data; + break; + case 2: //parameter 2 + m_par[m_state++] = data; + break; + } + + switch (m_par[0] & 0x0f) + { + case LCD_BYTE_INPUT: + case LCD_CHAR_OUTPUT: + { + if (m_state == 1) + m_bank = BIT(data, 4); + else if (m_state == 2) + m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); + else if (m_state == 3) + m_offset += ((data & 0x03) * 96); + } + break; + case LCD_BYTE_OUTPUT: + { + if (m_state == 1) + m_bank = BIT(data, 4); + else if (m_state == 2) + m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); + else if (m_state == 3) + m_offset += ((data & 0x03) * 96); + } + break; + case LCD_ON_OFF: + { + if (m_state == 1) + m_lcd_on = BIT(data, 4); + m_data_bus = 0xff; + m_state = 0; + } + break; + case LCD_SCROLL_CHAR_WIDTH: + { + if (m_state == 1) + { + m_char_width = 8-((data>>4)&3); + m_scroll = ((data>>6)&3); + } + + m_data_bus = 0xff; + m_state = 0; + } + break; + case LCD_CURSOR_STATUS: + { + if (m_state == 1) + m_cursor_status = data; + m_data_bus = 0xff; + m_state = 0; + } + break; + case LCD_CONTRAST: + { + if (m_state == 1) + m_contrast = (m_contrast & 0x00ffff) | (data<<16); + else if (m_state == 2) + m_contrast = (m_contrast & 0xff00ff) | (data<<8); + else if (m_state == 3) + { + m_contrast = (m_contrast & 0xffff00) | (data<<0); + m_state = 0; + } + + m_data_bus = 0xff; + } + break; + case LCD_IRQ_FREQUENCY: + { + if (m_state == 1) + { + UINT32 on_timer_rate; + + switch((data>>4) & 0x0f) + { + case 0x00: on_timer_rate = 16384; break; + case 0x01: on_timer_rate = 8; break; + case 0x02: on_timer_rate = 16; break; + case 0x03: on_timer_rate = 32; break; + case 0x04: on_timer_rate = 64; break; + case 0x05: on_timer_rate = 128; break; + case 0x06: on_timer_rate = 256; break; + case 0x07: on_timer_rate = 512; break; + case 0x08: on_timer_rate = 1024; break; + case 0x09: on_timer_rate = 2048; break; + case 0x0a: on_timer_rate = 4096; break; + case 0x0b: on_timer_rate = 4096; break; + default: on_timer_rate = 8192; break; + } + + m_on_timer->adjust(attotime::from_hz(m_clock/on_timer_rate), 0, attotime::from_hz(m_clock/on_timer_rate)); + } + m_data_bus = 0xff; + m_state = 0; + } + break; + case LCD_CURSOR_POSITION: + { + if (m_state == 1) + m_cursor_lcd = BIT(data, 4); //0:left lcd 1:right lcd; + else if (m_state == 2) + m_cursor_x = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); + else if (m_state == 3) + { + m_cursor_y = data & 0x03; + m_state = 0; + } + + m_data_bus = 0xff; + } + break; + } + + m_byte_count = 0; + m_data_bus = 0xff; + } + else + { + switch (m_par[0] & 0x0f) + { + case LCD_BYTE_INPUT: + { + if (((m_par[0]>>5) & 0x07) != 0x03) + break; + + m_offset %= 0x180; + m_data_bus = ((m_video_ram[m_bank][m_offset]<<4)&0xf0) | ((m_video_ram[m_bank][m_offset]>>4)&0x0f); + m_offset++; m_byte_count++; + } + break; + case LCD_BYTE_OUTPUT: + { + m_offset %= 0x180; + m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], data); + m_offset++; m_byte_count++; + + m_data_bus = 0xff; + } + break; + case LCD_CHAR_OUTPUT: + { + int char_pos = data*8; + + for (int i=0; i<m_char_width; i++) + { + m_offset %= 0x180; + m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], get_char(char_pos)); + m_offset++; char_pos++; + } + + m_byte_count++; + m_data_bus = 0xff; + } + break; + case LCD_CURSOR_GRAPHIC: + if (m_byte_count<8) + { + m_cursor[m_byte_count] = data; + m_byte_count++; + m_data_bus = 0xff; + } + break; + case LCD_CURSOR_CHAR: + if (m_byte_count<1) + { + UINT8 char_code = ((data<<4)&0xf0) | ((data>>4)&0x0f); + + for (int i=0; i<8; i++) + m_cursor[i] = get_char(char_code*8 + i); + + m_byte_count++; + m_data_bus = 0xff; + } + break; + case LCD_USER_CHARACTER: + if (m_byte_count<8) + { + m_custom_char[(m_par[1]&0x03)][m_byte_count] = data; + m_byte_count++; + m_data_bus = 0xff; + } + break; + default: + m_data_bus = 0xff; + } + + m_state=0; + } +} + +UINT8 hd44352_device::data_read() +{ + return m_data_bus; +} |