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