1 // license:BSD-3-Clause
2 // copyright-holders:hap
3 /*
4 
5 Hughes HLCD 0515 family LCD Driver
6 
7 0515: 25 columns(also size of buffer/ram)
8 0569: 24 columns, display blank has no effect(instead it's external with VDRIVE?)
9 0530: specifications unknown, pinout seems similar to 0569
10 0601: specifications unknown, pinout seems similar to 0569
11 
12 TODO:
13 - Does DATA OUT pin function the same on each chip? The 0515 datasheet says that
14   the 25th column is output first, but on 0569(no datasheet available) it's reversed.
15 
16 */
17 
18 #include "emu.h"
19 #include "video/hlcd0515.h"
20 
21 
22 DEFINE_DEVICE_TYPE(HLCD0515, hlcd0515_device, "hlcd0515", "Hughes HLCD 0515 LCD Driver")
23 DEFINE_DEVICE_TYPE(HLCD0569, hlcd0569_device, "hlcd0569", "Hughes HLCD 0569 LCD Driver")
24 DEFINE_DEVICE_TYPE(HLCD0530, hlcd0530_device, "hlcd0530", "Hughes HLCD 0530 LCD Driver")
25 DEFINE_DEVICE_TYPE(HLCD0601, hlcd0601_device, "hlcd0601", "Hughes HLCD 0601 LCD Driver")
26 
27 //-------------------------------------------------
28 //  constructor
29 //-------------------------------------------------
30 
hlcd0515_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,u32 clock,u8 colmax)31 hlcd0515_device::hlcd0515_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 colmax) :
32 	device_t(mconfig, type, tag, owner, clock),
33 	m_colmax(colmax),
34 	m_write_cols(*this), m_write_data(*this)
35 { }
36 
hlcd0515_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)37 hlcd0515_device::hlcd0515_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
38 	hlcd0515_device(mconfig, HLCD0515, tag, owner, clock, 25)
39 { }
40 
hlcd0569_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)41 hlcd0569_device::hlcd0569_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
42 	hlcd0515_device(mconfig, HLCD0569, tag, owner, clock, 24)
43 { }
44 
hlcd0530_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)45 hlcd0530_device::hlcd0530_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
46 	hlcd0515_device(mconfig, HLCD0530, tag, owner, clock, 24)
47 { }
48 
hlcd0601_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)49 hlcd0601_device::hlcd0601_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
50 	hlcd0515_device(mconfig, HLCD0601, tag, owner, clock, 24)
51 { }
52 
53 
54 
55 //-------------------------------------------------
56 //  device_start - device-specific startup
57 //-------------------------------------------------
58 
device_start()59 void hlcd0515_device::device_start()
60 {
61 	// resolve callbacks
62 	m_write_cols.resolve_safe();
63 	m_write_data.resolve_safe();
64 
65 	// timer
66 	m_lcd_timer = timer_alloc();
67 	attotime period = attotime::from_hz(clock() / 2);
68 	m_lcd_timer->adjust(period, 0, period);
69 
70 	// zerofill
71 	m_cs = 0;
72 	m_clk = 0;
73 	m_data = 0;
74 	m_dataout = 0;
75 	m_count = 0;
76 	m_control = 0;
77 	m_blank = false;
78 	m_rowmax = 0;
79 	m_rowout = 0;
80 	m_rowsel = 0;
81 	m_buffer = 0;
82 	memset(m_ram, 0, sizeof(m_ram));
83 
84 	// register for savestates
85 	save_item(NAME(m_cs));
86 	save_item(NAME(m_clk));
87 	save_item(NAME(m_data));
88 	save_item(NAME(m_dataout));
89 	save_item(NAME(m_count));
90 	save_item(NAME(m_control));
91 	save_item(NAME(m_blank));
92 	save_item(NAME(m_rowmax));
93 	save_item(NAME(m_rowout));
94 	save_item(NAME(m_rowsel));
95 	save_item(NAME(m_buffer));
96 	save_item(NAME(m_ram));
97 }
98 
99 
100 
101 //-------------------------------------------------
102 //  device_timer - handle timer events
103 //-------------------------------------------------
104 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)105 void hlcd0515_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
106 {
107 	if (m_rowout > m_rowmax)
108 		m_rowout = 0;
109 
110 	// write to COL/ROW pins
111 	m_write_cols(m_rowout, m_blank ? 0 : m_ram[m_rowout], ~0);
112 	m_rowout++;
113 }
114 
115 
116 
117 //-------------------------------------------------
118 //  handlers
119 //-------------------------------------------------
120 
set_control()121 void hlcd0515_device::set_control()
122 {
123 	// clock 0,1,2: row select
124 	m_rowsel = m_control >> 2 & 7;
125 
126 	// clock 3(,4): initialize
127 	if (m_control & 2)
128 	{
129 		m_rowmax = m_rowsel;
130 		m_blank = bool(~m_control & 1);
131 	}
132 
133 	// clock 4: read/write mode
134 	if (m_control & 1)
135 	{
136 		m_buffer = m_ram[m_rowsel];
137 		clock_data();
138 	}
139 	else
140 		m_buffer = 0;
141 }
142 
set_control()143 void hlcd0569_device::set_control()
144 {
145 	hlcd0515_device::set_control();
146 	m_blank = false; // 0569 doesn't support display blanking
147 }
148 
149 
clock_data(int col)150 void hlcd0515_device::clock_data(int col)
151 {
152 	if (m_control & 1)
153 	{
154 		m_dataout = m_buffer & 1;
155 		m_write_data(m_dataout);
156 
157 		m_buffer >>= 1;
158 	}
159 	else
160 	{
161 		if (col < m_colmax)
162 			m_buffer >>= 1;
163 
164 		// always write last column
165 		u32 mask = 1 << (m_colmax - 1);
166 		m_buffer = (m_buffer & ~mask) | (m_data ? mask : 0);
167 	}
168 }
169 
170 
WRITE_LINE_MEMBER(hlcd0515_device::clock_w)171 WRITE_LINE_MEMBER(hlcd0515_device::clock_w)
172 {
173 	state = (state) ? 1 : 0;
174 
175 	// clock/shift data on falling edge
176 	if (!m_cs && !state && m_clk)
177 	{
178 		if (m_count < 5)
179 		{
180 			// 5-bit mode/control
181 			m_control = m_control << 1 | m_data;
182 			if (m_count == 4)
183 				set_control();
184 		}
185 
186 		else
187 			clock_data(m_count - 5);
188 
189 		if (m_count < (m_colmax + 5))
190 			m_count++;
191 	}
192 
193 	m_clk = state;
194 }
195 
196 
WRITE_LINE_MEMBER(hlcd0515_device::cs_w)197 WRITE_LINE_MEMBER(hlcd0515_device::cs_w)
198 {
199 	state = (state) ? 1 : 0;
200 
201 	// finish serial sequence on rising edge
202 	if (state && !m_cs)
203 	{
204 		// transfer to ram
205 		if (~m_control & 1)
206 			m_ram[m_rowsel] = m_buffer;
207 
208 		m_count = 0;
209 		m_control = 0;
210 	}
211 
212 	m_cs = state;
213 }
214