summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/hd44352.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/hd44352.cpp')
-rw-r--r--src/devices/video/hd44352.cpp439
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;
+}