summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/t6a04.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/t6a04.cpp')
-rw-r--r--src/devices/video/t6a04.cpp242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/devices/video/t6a04.cpp b/src/devices/video/t6a04.cpp
new file mode 100644
index 00000000000..89bf9cf716a
--- /dev/null
+++ b/src/devices/video/t6a04.cpp
@@ -0,0 +1,242 @@
+// license:BSD-3-Clause
+// copyright-holders:Sandro Ronco
+/***************************************************************************
+
+ Toshiba T6A04 LCD controller
+
+ TODO:
+ - busy flag
+ - contrast
+ - slave mode
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/t6a04.h"
+
+// devices
+const device_type T6A04 = &device_creator<t6a04_device>;
+
+//-------------------------------------------------
+// device_validity_check - perform validity checks
+// on this device
+//-------------------------------------------------
+
+void t6a04_device::device_validity_check(validity_checker &valid) const
+{
+ if (m_height == 0 || m_width == 0)
+ osd_printf_error("Configured with invalid parameter\n");
+}
+
+//**************************************************************************
+// live device
+//**************************************************************************
+
+//-------------------------------------------------
+// t6a04_device - constructor
+//-------------------------------------------------
+
+t6a04_device::t6a04_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, T6A04, "T6A04", tag, owner, clock, "t6a04", __FILE__),
+ m_height(0),
+ m_width(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void t6a04_device::device_start()
+{
+ save_item(NAME(m_busy_flag));
+ save_item(NAME(m_display_on));
+ save_item(NAME(m_contrast));
+ save_item(NAME(m_xpos));
+ save_item(NAME(m_ypos));
+ save_item(NAME(m_zpos));
+ save_item(NAME(m_active_counter));
+ save_item(NAME(m_direction));
+ save_item(NAME(m_word_len));
+ save_item(NAME(m_opa1));
+ save_item(NAME(m_opa2));
+ save_item(NAME(m_output_reg));
+ save_item(NAME(m_lcd_ram));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void t6a04_device::device_reset()
+{
+ //values taken from the datasheet
+ memset(m_lcd_ram, 0x00, sizeof(m_lcd_ram));
+ m_busy_flag = 0;
+ m_display_on = 0;
+ m_contrast = 0;
+ m_xpos = 0;
+ m_ypos = 0;
+ m_zpos = 0;
+ m_direction = 1;
+ m_active_counter = 1;
+ m_word_len = 1; //8bit mode
+ m_opa1 = 0;
+ m_opa2 = 0;
+ m_output_reg = 0;
+}
+
+
+//**************************************************************************
+// device interface
+//**************************************************************************
+
+UINT32 t6a04_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT8 ypages = m_width>>3;
+ UINT8 last_line = m_zpos + m_height;
+
+ if (m_display_on)
+ {
+ for (int y=0; y<ypages; y++)
+ for (int x=m_zpos; x<last_line; x++)
+ {
+ UINT8 data = m_lcd_ram[(x&0x3f)*15 + y];
+
+ for (int b=7; b>=0; b--)
+ {
+ bitmap.pix16(x&0x3f, y*8+b) = data & 1;
+ data>>=1;
+ }
+ }
+ }
+ else
+ {
+ bitmap.fill(0, cliprect);
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(t6a04_device::control_write)
+{
+ if ((data & 0xc0) == 0xc0) // SCE (set contrast)
+ {
+ m_contrast = data&0x3f;
+ }
+ else if ((data & 0xc0) == 0x80) // SXE (set x address)
+ {
+ m_xpos = data&0x3f;
+ }
+ else if ((data & 0xc0) == 0x40) // SZE (set z address)
+ {
+ m_zpos = data&0x3f;
+ }
+ else if ((data & 0xe0) == 0x20) // SYE (set y address)
+ {
+ m_ypos = data&0x1f;
+ }
+ else if ((data & 0xf8) == 0x18) // CHE (test mode)
+ {
+ //???
+ }
+ else if ((data & 0xf8) == 0x10) // OPA1 (op-amp control 1)
+ {
+ m_opa1 = data & 3;
+ }
+ else if ((data & 0xf8) == 0x08) // OPA2 (op-amp control 2)
+ {
+ m_opa2 = data & 3;
+ }
+ else if ((data & 0xfc) == 0x04) // UDE (up/down mode)
+ {
+ m_active_counter = (data & 0x02) >> 1;
+ m_direction = (data & 0x01) ? +1 : -1;
+ }
+ else if ((data & 0xfe) == 0x02) // DPE (display on/off)
+ {
+ m_display_on = data & 1;
+ }
+ else if ((data & 0xfe) == 0x00) // 86E (word length)
+ {
+ m_word_len = data & 1;
+ }
+}
+
+READ8_MEMBER(t6a04_device::control_read)
+{
+ /*
+ status read
+ x--- ---- busy
+ -x-- ---- 8/6 mode
+ --x- ---- display on/off
+ ---x ---- reset state
+ ---- xx-- unused (always 0)
+ ---- --x- x/y counter
+ ---- ---x up/down mode
+ */
+
+ return (m_busy_flag<<7) | (m_word_len<<6) | (m_display_on<<5) | (m_active_counter<<1) | (m_direction == 1 ? 1 : 0);
+}
+
+WRITE8_MEMBER(t6a04_device::data_write)
+{
+ if (m_word_len)
+ {
+ //8bit mode
+ m_lcd_ram[m_xpos*15 + m_ypos] = data;
+ }
+ else
+ {
+ //6bit mode
+ data = data<<0x02;
+ UINT8 start_bit = m_ypos * 6;
+ UINT8 pos_bit = start_bit & 0x07;
+ UINT8 *ti82_video = &m_lcd_ram[(m_xpos*15)+(start_bit>>3)];
+
+ ti82_video[0] = (ti82_video[0] & ~(0xFC>>pos_bit)) | (data>>pos_bit);
+ if(pos_bit>0x02)
+ ti82_video[1] = (ti82_video[1] & ~(0xFC<<(8-pos_bit))) | (data<<(8-pos_bit));
+ }
+
+ if (m_active_counter)
+ m_ypos = (m_ypos + m_direction) & 0x1f;
+ else
+ m_xpos = (m_xpos + m_direction) & 0x3f;
+
+}
+
+READ8_MEMBER(t6a04_device::data_read)
+{
+ UINT8 data = m_output_reg;
+ UINT8 output_reg;
+
+ if (m_word_len)
+ {
+ //8bit mode
+ output_reg = m_lcd_ram[m_xpos*15 + m_ypos];
+ }
+ else
+ {
+ //6bit mode
+ UINT8 start_bit = m_ypos * 6;
+ UINT8 pos_bit = start_bit & 7;
+ UINT8 *ti82_video = &m_lcd_ram[(m_xpos*15)+(start_bit>>3)];
+
+ output_reg = ((((*ti82_video)<<8)+ti82_video[1])>>(10-pos_bit));
+ }
+
+ if (!space.debugger_access())
+ {
+ m_output_reg = output_reg;
+
+ if (m_active_counter)
+ m_ypos = (m_ypos + m_direction) & 0x1f;
+ else
+ m_xpos = (m_xpos + m_direction) & 0x3f;
+ }
+
+ return data;
+}