1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4 
5     OKI MSM6255 Dot Matrix LCD Controller implementation
6 
7 **********************************************************************/
8 
9 #include "emu.h"
10 #include "msm6255.h"
11 
12 //#define VERBOSE 1
13 #include "logmacro.h"
14 
15 
16 //**************************************************************************
17 //  MACROS / CONSTANTS
18 //**************************************************************************
19 
20 #define MOR_GRAPHICS        0x01
21 #define MOR_4_BIT_PARALLEL  0x02
22 #define MOR_2_BIT_PARALLEL  0x04
23 #define MOR_DISPLAY_ON      0x08
24 #define MOR_CURSOR_BLINK    0x10
25 #define MOR_CURSOR_ON       0x20
26 #define MOR_BLINK_TIME_16   0x40
27 
28 
29 #define PR_HP_4             0x03
30 #define PR_HP_5             0x04
31 #define PR_HP_6             0x05
32 #define PR_HP_7             0x06
33 #define PR_HP_8             0x07
34 #define PR_HP_MASK          0x07
35 #define PR_VP_MASK          0xf0
36 
37 
38 #define HNR_HN_MASK         0x7f
39 
40 
41 #define DVR_DN_MASK         0x7f
42 
43 
44 #define CPR_CPD_MASK        0x0f
45 #define CPR_CPU_MASK        0xf0
46 
47 
48 
49 //**************************************************************************
50 //  DEVICE DEFINITIONS
51 //**************************************************************************
52 
53 // device type definition
54 DEFINE_DEVICE_TYPE(MSM6255, msm6255_device, "msm6255", "Oki MSM6255 LCD Controller")
55 
56 // I/O map
map(address_map & map)57 void msm6255_device::map(address_map &map)
58 {
59 	map(0x00, 0x00).rw(FUNC(msm6255_device::dr_r), FUNC(msm6255_device::dr_w));
60 	map(0x01, 0x01).rw(FUNC(msm6255_device::ir_r), FUNC(msm6255_device::ir_w));
61 }
62 
63 // default address map
msm6255(address_map & map)64 void msm6255_device::msm6255(address_map &map)
65 {
66 	if (!has_configured_map(0))
67 		map(0x00000, 0xfffff).ram();
68 }
69 
70 
71 
72 //**************************************************************************
73 //  LIVE DEVICE
74 //**************************************************************************
75 
76 //-------------------------------------------------
77 //  msm6255_device - constructor
78 //-------------------------------------------------
79 
msm6255_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)80 msm6255_device::msm6255_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
81 	device_t(mconfig, MSM6255, tag, owner, clock),
82 	device_memory_interface(mconfig, *this),
83 	device_video_interface(mconfig, *this),
84 	m_space_config("videoram", ENDIANNESS_LITTLE, 8, 20, 0, address_map_constructor(FUNC(msm6255_device::msm6255), this)),
85 	m_cursor(0)
86 {
87 }
88 
89 
90 //-------------------------------------------------
91 //  device_start - device-specific startup
92 //-------------------------------------------------
93 
device_start()94 void msm6255_device::device_start()
95 {
96 	// register for state saving
97 	save_item(NAME(m_ir));
98 	save_item(NAME(m_mor));
99 	save_item(NAME(m_pr));
100 	save_item(NAME(m_hnr));
101 	save_item(NAME(m_dvr));
102 	save_item(NAME(m_cpr));
103 	save_item(NAME(m_slr));
104 	save_item(NAME(m_sur));
105 	save_item(NAME(m_clr));
106 	save_item(NAME(m_cur));
107 	save_item(NAME(m_cursor));
108 	save_item(NAME(m_frame));
109 }
110 
111 
112 //-------------------------------------------------
113 //  device_reset - device-specific reset
114 //-------------------------------------------------
115 
device_reset()116 void msm6255_device::device_reset()
117 {
118 	m_frame = 0;
119 }
120 
121 
122 //-------------------------------------------------
123 //  memory_space_config - return a description of
124 //  any address spaces owned by this device
125 //-------------------------------------------------
126 
memory_space_config() const127 device_memory_interface::space_config_vector msm6255_device::memory_space_config() const
128 {
129 	return space_config_vector {
130 		std::make_pair(0, &m_space_config)
131 	};
132 }
133 
134 
135 //-------------------------------------------------
136 //  ir_r -
137 //-------------------------------------------------
138 
ir_r()139 uint8_t msm6255_device::ir_r()
140 {
141 	return m_ir;
142 }
143 
144 
145 //-------------------------------------------------
146 //  ir_w -
147 //-------------------------------------------------
148 
ir_w(uint8_t data)149 void msm6255_device::ir_w(uint8_t data)
150 {
151 	m_ir = data & 0x0f;
152 }
153 
154 
155 //-------------------------------------------------
156 //  dr_r -
157 //-------------------------------------------------
158 
dr_r()159 uint8_t msm6255_device::dr_r()
160 {
161 	uint8_t data = 0;
162 
163 	switch (m_ir)
164 	{
165 	case REGISTER_MOR:
166 		break; // write-only
167 
168 	case REGISTER_PR:
169 		data = m_pr;
170 		break;
171 
172 	case REGISTER_HNR:
173 		data = m_hnr;
174 		break;
175 
176 	case REGISTER_DVR:
177 		break; // write-only
178 
179 	case REGISTER_CPR:
180 		data = m_cpr;
181 		break;
182 
183 	case REGISTER_SLR:
184 		data = m_slr;
185 		break;
186 
187 	case REGISTER_SUR:
188 		data = m_sur;
189 		break;
190 
191 	case REGISTER_CLR:
192 		data = m_clr;
193 		break;
194 
195 	case REGISTER_CUR:
196 		data = m_cur;
197 		break;
198 	}
199 
200 	return data;
201 }
202 
203 
204 //-------------------------------------------------
205 //  dr_w -
206 //-------------------------------------------------
207 
dr_w(uint8_t data)208 void msm6255_device::dr_w(uint8_t data)
209 {
210 	switch (m_ir)
211 	{
212 	case REGISTER_MOR:
213 		m_mor = data & 0x7f;
214 		break;
215 
216 	case REGISTER_PR:
217 		m_pr = data & 0xf7;
218 		break;
219 
220 	case REGISTER_HNR:
221 		m_hnr = data & 0x7f;
222 		break;
223 
224 	case REGISTER_DVR:
225 		m_dvr = data;
226 		break;
227 
228 	case REGISTER_CPR:
229 		m_cpr = data;
230 		break;
231 
232 	case REGISTER_SLR:
233 		m_slr = data;
234 		break;
235 
236 	case REGISTER_SUR:
237 		m_sur = data;
238 		break;
239 
240 	case REGISTER_CLR:
241 		m_clr = data;
242 		break;
243 
244 	case REGISTER_CUR:
245 		m_cur = data;
246 		break;
247 	}
248 }
249 
250 
251 //-------------------------------------------------
252 //  read_byte -
253 //-------------------------------------------------
254 
read_byte(uint16_t ma,uint8_t ra)255 uint8_t msm6255_device::read_byte(uint16_t ma, uint8_t ra)
256 {
257 	offs_t offset;
258 
259 	if (m_mor & MOR_GRAPHICS)
260 	{
261 		offset = ma;
262 	}
263 	else
264 	{
265 		offset = ((offs_t)ma << 4) | ra;
266 	}
267 
268 	return space().read_byte(offset);
269 }
270 
271 
272 //-------------------------------------------------
273 //  update_cursor -
274 //-------------------------------------------------
275 
update_cursor()276 void msm6255_device::update_cursor()
277 {
278 	if (m_mor & MOR_CURSOR_ON)
279 	{
280 		if (m_mor & MOR_CURSOR_BLINK)
281 		{
282 			if (m_mor & MOR_BLINK_TIME_16)
283 			{
284 				if (m_frame == 16)
285 				{
286 					m_cursor = !m_cursor;
287 					m_frame = 0;
288 				}
289 				else
290 				{
291 					m_frame++;
292 				}
293 			}
294 			else
295 			{
296 				if (m_frame == 32)
297 				{
298 					m_cursor = !m_cursor;
299 					m_frame = 0;
300 				}
301 				else
302 				{
303 					m_frame++;
304 				}
305 			}
306 		}
307 		else
308 		{
309 			m_cursor = 1;
310 		}
311 	}
312 	else
313 	{
314 		m_cursor = 0;
315 	}
316 }
317 
318 
319 //-------------------------------------------------
320 //  draw_scanline -
321 //-------------------------------------------------
322 
draw_scanline(bitmap_ind16 & bitmap,const rectangle & cliprect,int y,uint16_t ma,uint8_t ra)323 void msm6255_device::draw_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, uint16_t ma, uint8_t ra)
324 {
325 	uint8_t hp = (m_pr & PR_HP_MASK) + 1;
326 	uint8_t hn = (m_hnr & HNR_HN_MASK) + 1;
327 	uint8_t cpu = m_cpr & CPR_CPU_MASK;
328 	uint8_t cpd = m_cpr & CPR_CPD_MASK;
329 	uint16_t car = (m_cur << 8) | m_clr;
330 
331 	for (int sx = 0; sx < hn; sx++)
332 	{
333 		uint8_t data = read_byte(ma, ra);
334 
335 		if (m_cursor)
336 		{
337 			if (ma == car)
338 			{
339 				if (ra >= cpu && ra <= cpd)
340 				{
341 					data ^= 0xff;
342 				}
343 			}
344 		}
345 
346 		for (int x = 0; x < hp; x++)
347 		{
348 			bitmap.pix(y, (sx * hp) + x) = BIT(data, 7);
349 
350 			data <<= 1;
351 		}
352 
353 		ma++;
354 	}
355 }
356 
357 
358 //-------------------------------------------------
359 //  update_graphics -
360 //-------------------------------------------------
361 
update_graphics(bitmap_ind16 & bitmap,const rectangle & cliprect)362 void msm6255_device::update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect)
363 {
364 	uint8_t hn = (m_hnr & HNR_HN_MASK) + 1;
365 	uint8_t nx = (m_dvr & DVR_DN_MASK) + 1;
366 	uint16_t sar = (m_sur << 8) | m_slr;
367 
368 	int y;
369 
370 	m_cursor = 0;
371 	m_frame = 0;
372 
373 	for (y = 0; y < nx; y++)
374 	{
375 		// draw upper half scanline
376 		uint16_t ma = sar + (y * hn);
377 		draw_scanline(bitmap, cliprect, y, ma);
378 
379 		// draw lower half scanline
380 		ma = sar + ((y + nx) * hn);
381 		draw_scanline(bitmap, cliprect, y + nx, ma);
382 	}
383 }
384 
385 
386 //-------------------------------------------------
387 //  update_text -
388 //-------------------------------------------------
389 
update_text(bitmap_ind16 & bitmap,const rectangle & cliprect)390 void msm6255_device::update_text(bitmap_ind16 &bitmap, const rectangle &cliprect)
391 {
392 	uint8_t hn = (m_hnr & HNR_HN_MASK) + 1;
393 	uint8_t vp = (m_pr & PR_VP_MASK) + 1;
394 	uint8_t nx = (m_dvr & DVR_DN_MASK) + 1;
395 	uint16_t sar = (m_sur << 8) | m_slr;
396 
397 	int sy, y;
398 
399 	update_cursor();
400 
401 	for (sy = 0; sy < nx; sy++)
402 	{
403 		for (y = 0; y < vp; y++)
404 		{
405 			// draw upper half scanline
406 			uint16_t ma = sar + ((sy * vp) + y) * hn;
407 			draw_scanline(bitmap, cliprect, (sy * vp) + y, ma, y);
408 
409 			// draw lower half scanline
410 			ma = sar + (((sy + nx) * vp) + y) * hn;
411 			draw_scanline(bitmap, cliprect, (sy * vp) + y, ma, y);
412 		}
413 	}
414 }
415 
416 
417 //-------------------------------------------------
418 //  update_screen - update screen
419 //-------------------------------------------------
420 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)421 uint32_t msm6255_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
422 {
423 	if (m_mor & MOR_DISPLAY_ON)
424 	{
425 		if (m_mor & MOR_GRAPHICS)
426 		{
427 			update_graphics(bitmap, cliprect);
428 		}
429 		else
430 		{
431 			update_text(bitmap, cliprect);
432 		}
433 	}
434 	else
435 	{
436 		bitmap.fill(0, cliprect);
437 	}
438 
439 	return 0;
440 }
441