xref: /netbsd-src/sys/arch/x68k/dev/ite_tv.c (revision d78516774c855654490144bf49a71476e97b5cde)
1 /*	$NetBSD: ite_tv.c,v 1.21 2024/10/05 03:56:54 isaki Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Masaru Oki.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Masaru Oki.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: ite_tv.c,v 1.21 2024/10/05 03:56:54 isaki Exp $");
35 
36 #include "opt_ite.h"
37 
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/proc.h>
41 #include <sys/systm.h>
42 
43 #include <machine/bus.h>
44 #include <machine/grfioctl.h>
45 
46 #include <arch/x68k/x68k/iodevice.h>
47 #include <arch/x68k/dev/itevar.h>
48 #include <arch/x68k/dev/grfvar.h>
49 #include <arch/x68k/dev/mfp.h>
50 
51 /*
52  * ITE device dependent routine for X680x0 Text-Video framebuffer.
53  * Use X680x0 ROM fixed width font (8x16)
54  */
55 
56 #define CRTC    (IODEVbase->io_crtc)
57 
58 /*
59  * font constant
60  */
61 #define FONTWIDTH   8
62 #define FONTHEIGHT  16
63 #define UNDERLINE   14
64 
65 /*
66  * framebuffer constant
67  */
68 #define PLANEWIDTH  1024
69 #define PLANEHEIGHT 1024
70 #define PLANELINES  (PLANEHEIGHT / FONTHEIGHT)
71 #define ROWBYTES    (PLANEWIDTH  / FONTWIDTH)
72 #define PLANESIZE   (PLANEHEIGHT * ROWBYTES)
73 
74 static u_int  tv_top;
75 static uint8_t *tv_row[PLANELINES];
76 #if defined(ITE_SIXEL)
77 static uint8_t *tv_end;
78 #endif
79 static uint8_t *tv_font[256];
80 static volatile uint8_t *tv_kfont[0x7f];
81 
82 uint8_t kern_font[256 * FONTHEIGHT];
83 
84 #define PHYSLINE(y)  ((tv_top + (y)) % PLANELINES)
85 #define ROWOFFSET(y) ((y) * FONTHEIGHT * ROWBYTES)
86 #define CHADDR(y, x) (tv_row[PHYSLINE(y)] + (x))
87 
88 #define SETGLYPH(to,from)	\
89 	memcpy(&kern_font[(from) * 16],&kern_font[(to) * 16], 16)
90 #define KFONTBASE(left)   ((left) * 32 * 0x5e - 0x21 * 32)
91 
92 /* prototype */
93 static void tv_putc(struct ite_softc *, int, int, int, int);
94 static void tv_cursor(struct ite_softc *, int);
95 static void tv_clear(struct ite_softc *, int, int, int, int);
96 static void tv_scroll(struct ite_softc *, int, int, int, int);
97 #if defined(ITE_SIXEL)
98 static void tv_sixel(struct ite_softc *, int, int);
99 #endif
100 
101 static inline uint32_t expbits(uint32_t);
102 static inline void txrascpy(uint8_t, uint8_t, int16_t, uint16_t);
103 
104 static inline void
105 txrascpy(uint8_t src, uint8_t dst, int16_t size, uint16_t mode)
106 {
107 	/*int s;*/
108 	uint16_t saved_r21 = CRTC.r21;
109 	int8_t d;
110 
111 	d = ((mode & 0x8000) != 0) ? -1 : 1;
112 	src *= FONTHEIGHT / 4;
113 	dst *= FONTHEIGHT / 4;
114 	size *= 4;
115 	if (d < 0) {
116 		src += (FONTHEIGHT / 4) - 1;
117 		dst += (FONTHEIGHT / 4) - 1;
118 	}
119 
120 	/* specify same time write mode & page */
121 	CRTC.r21 = (mode & 0x0f) | 0x0100;
122 	/*mfp.ddr = 0;*/			/* port is input */
123 
124 	/*s = splhigh();*/
125 	while (--size >= 0) {
126 		/* wait for hsync */
127 		mfp_wait_for_hsync();
128 		CRTC.r22 = (src << 8) | dst;	/* specify raster number */
129 		/* start raster copy */
130 		CRTC.crtctrl = 0x0008;
131 
132 		src += d;
133 		dst += d;
134 	}
135 	/*splx(s);*/
136 
137 	/* wait for hsync */
138 	mfp_wait_for_hsync();
139 
140 	/* stop raster copy */
141 	CRTC.crtctrl = 0x0000;
142 
143 	CRTC.r21 = saved_r21;
144 }
145 
146 /*
147  * Change glyphs from SRAM switch.
148  */
149 void
150 ite_set_glyph(void)
151 {
152 	uint8_t glyph = IODEVbase->io_sram[0x59];
153 
154 	if ((glyph & 4) != 0)
155 		SETGLYPH(0x82, '|');
156 	if ((glyph & 2) != 0)
157 		SETGLYPH(0x81, '~');
158 	if ((glyph & 1) != 0)
159 		SETGLYPH(0x80, '\\');
160 }
161 
162 /*
163  * Initialize
164  */
165 void
166 tv_init(struct ite_softc *ip)
167 {
168 	short i;
169 
170 	/*
171 	 * initialize private variables
172 	 */
173 	tv_top = 0;
174 	for (i = 0; i < PLANELINES; i++)
175 		tv_row[i] =
176 		    (void *)__UNVOLATILE(&IODEVbase->tvram[ROWOFFSET(i)]);
177 #if defined(ITE_SIXEL)
178 	tv_end = (void *)__UNVOLATILE(&IODEVbase->tvram[ROWOFFSET(i)]);
179 #endif
180 	/* shadow ANK font */
181 	memcpy(kern_font, (void *)&IODEVbase->cgrom0_8x16, 256 * FONTHEIGHT);
182 	ite_set_glyph();
183 	/* set font address cache */
184 	for (i = 0; i < 256; i++)
185 		tv_font[i] = &kern_font[i * FONTHEIGHT];
186 	for (i = 0x21; i < 0x30; i++)
187 		tv_kfont[i] = &IODEVbase->cgrom0_16x16[KFONTBASE(i-0x21)];
188 	for (; i < 0x50; i++)
189 		tv_kfont[i] = &IODEVbase->cgrom1_16x16[KFONTBASE(i-0x30)];
190 	for (; i < 0x7f; i++)
191 		tv_kfont[i] = &IODEVbase->cgrom2_16x16[KFONTBASE(i-0x50)];
192 
193 	/*
194 	 * initialize part of ip
195 	 */
196 	ip->cols = ip->grf->g_display.gd_dwidth  / FONTWIDTH;
197 	ip->rows = ip->grf->g_display.gd_dheight / FONTHEIGHT;
198 	/* set draw routine dynamically */
199 	ip->isw->ite_putc   = tv_putc;
200 	ip->isw->ite_cursor = tv_cursor;
201 	ip->isw->ite_clear  = tv_clear;
202 	ip->isw->ite_scroll = tv_scroll;
203 #if defined(ITE_SIXEL)
204 	ip->isw->ite_sixel  = tv_sixel;
205 #endif
206 
207 	/*
208 	 * Initialize colormap
209 	 */
210 #define RED   (0x1f << 6)
211 #define BLUE  (0x1f << 1)
212 #define GREEN (0x1f << 11)
213 	IODEVbase->tpalet[0] = 0;			/* black */
214 	IODEVbase->tpalet[1] = 1 | RED;			/* red */
215 	IODEVbase->tpalet[2] = 1 | GREEN;		/* green */
216 	IODEVbase->tpalet[3] = 1 | RED | GREEN;		/* yellow */
217 	IODEVbase->tpalet[4] = 1 | BLUE;		/* blue */
218 	IODEVbase->tpalet[5] = 1 | BLUE | RED;		/* magenta */
219 	IODEVbase->tpalet[6] = 1 | BLUE | GREEN;	/* cyan */
220 	IODEVbase->tpalet[7] = 1 | BLUE | RED | GREEN;	/* white */
221 }
222 
223 /*
224  * Deinitialize
225  */
226 void
227 tv_deinit(struct ite_softc *ip)
228 {
229 
230 	ip->flags &= ~ITE_INITED; /* XXX? */
231 }
232 
233 static inline uint8_t *tv_getfont(int, int);
234 typedef void tv_putcfunc(struct ite_softc *, int, char *);
235 static tv_putcfunc tv_putc_nm;
236 static tv_putcfunc tv_putc_in;
237 static tv_putcfunc tv_putc_ul;
238 static tv_putcfunc tv_putc_ul_in;
239 static tv_putcfunc tv_putc_bd;
240 static tv_putcfunc tv_putc_bd_in;
241 static tv_putcfunc tv_putc_bd_ul;
242 static tv_putcfunc tv_putc_bd_ul_in;
243 
244 static tv_putcfunc *putc_func[ATTR_ALL + 1] = {
245 	[ATTR_NOR]					= tv_putc_nm,
246 	[ATTR_INV]					= tv_putc_in,
247 	[ATTR_UL]					= tv_putc_ul,
248 	[ATTR_INV | ATTR_UL]				= tv_putc_ul_in,
249 	[ATTR_BOLD]					= tv_putc_bd,
250 	[ATTR_BOLD | ATTR_INV]				= tv_putc_bd_in,
251 	[ATTR_BOLD | ATTR_UL]				= tv_putc_bd_ul,
252 	[ATTR_BOLD | ATTR_UL | ATTR_INV]		= tv_putc_bd_ul_in,
253 	/* no support for blink */
254 	[ATTR_BLINK]					= tv_putc_nm,
255 	[ATTR_BLINK | ATTR_INV]				= tv_putc_in,
256 	[ATTR_BLINK | ATTR_UL]				= tv_putc_ul,
257 	[ATTR_BLINK | ATTR_UL | ATTR_INV]		= tv_putc_ul_in,
258 	[ATTR_BLINK | ATTR_BOLD]			= tv_putc_bd,
259 	[ATTR_BLINK | ATTR_BOLD | ATTR_INV]		= tv_putc_bd_in,
260 	[ATTR_BLINK | ATTR_BOLD | ATTR_UL]		= tv_putc_bd_ul,
261 	[ATTR_BLINK | ATTR_BOLD | ATTR_UL | ATTR_INV]	= tv_putc_bd_ul_in,
262 };
263 
264 /*
265  * simple put character function
266  */
267 static void
268 tv_putc(struct ite_softc *ip, int ch, int y, int x, int mode)
269 {
270 	uint8_t *p = CHADDR(y, x);
271 	short fh;
272 
273 	/* multi page write mode */
274 	CRTC.r21 = 0x0100 | ip->fgcolor << 4;
275 
276 	/* draw plane */
277 	putc_func[mode](ip, ch, p);
278 
279 	/* erase plane */
280 	CRTC.r21 ^= 0x00f0;
281 	if (ip->save_char) {
282 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
283 			*(uint16_t *)p = 0;
284 	} else {
285 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
286 			*p = 0;
287 	}
288 
289 	/* crtc mode reset */
290 	CRTC.r21 = 0;
291 }
292 
293 static inline uint8_t *
294 tv_getfont(int cset, int ch)
295 {
296 
297 	if (cset == CSET_JISKANA) {
298 		ch |= 0x80;
299 	} else if (cset == CSET_DECGRAPH) {
300 		if (ch < 0x80) {
301 			ch = ite_decgraph2ascii[ch];
302 		}
303 	}
304 
305 	return tv_font[ch];
306 }
307 
308 static void
309 tv_putc_nm(struct ite_softc *ip, int ch, char *p)
310 {
311 	short fh, hi, lo;
312 	volatile uint16_t *kf;
313 	uint8_t *f;
314 
315 	hi = ip->save_char & 0x7f;
316 	lo = ch & 0x7f;
317 
318 	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
319 		/* multibyte character */
320 		kf = (volatile uint16_t *)tv_kfont[hi];
321 		kf += lo * FONTHEIGHT;
322 		/* draw plane */
323 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
324 			*(uint16_t *)p = *kf++;
325 		return;
326 	}
327 
328 	/* singlebyte character */
329 	f = tv_getfont(*ip->GL, ch);
330 
331 	/* draw plane */
332 	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
333 		*p = *f++;
334 }
335 
336 static void
337 tv_putc_in(struct ite_softc *ip, int ch, char *p)
338 {
339 	short fh, hi, lo;
340 	volatile uint16_t *kf;
341 	uint8_t *f;
342 
343 	hi = ip->save_char & 0x7f;
344 	lo = ch & 0x7f;
345 
346 	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
347 		/* multibyte character */
348 		kf = (volatile uint16_t *)tv_kfont[hi];
349 		kf += lo * FONTHEIGHT;
350 		/* draw plane */
351 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
352 			*(uint16_t *)p = ~*kf++;
353 		return;
354 	}
355 
356 	/* singlebyte character */
357 	f = tv_getfont(*ip->GL, ch);
358 
359 	/* draw plane */
360 	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
361 		*p = ~*f++;
362 }
363 
364 static void
365 tv_putc_bd(struct ite_softc *ip, int ch, char *p)
366 {
367 	short fh, hi, lo;
368 	u_int data;
369 	volatile uint16_t *kf;
370 	uint8_t *f;
371 
372 	hi = ip->save_char & 0x7f;
373 	lo = ch & 0x7f;
374 
375 	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
376 		/* multibyte character */
377 		kf = (volatile uint16_t *)tv_kfont[hi];
378 		kf += lo * FONTHEIGHT;
379 		/* draw plane */
380 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
381 			data = *kf++;
382 			*(uint16_t *)p = data | (data >> 1);
383 		}
384 		return;
385 	}
386 
387 	/* singlebyte character */
388 	f = tv_getfont(*ip->GL, ch);
389 
390 	/* draw plane */
391 	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
392 		data = *f++;
393 		*p = data | (data >> 1);
394 	}
395 }
396 
397 static inline uint32_t
398 expbits(uint32_t data)
399 {
400 	int i;
401 	u_int nd = 0;
402 
403 	if ((data & 1) != 0)
404 		nd |= 0x02;
405 	for (i = 1; i < 32; i++) {
406 		if ((data & (1 << i)) != 0)
407 			nd |= 0x5 << (i - 1);
408 	}
409 	nd &= ~data;
410 	return ~nd;
411 }
412 
413 static void
414 tv_putc_ul(struct ite_softc *ip, int ch, char *p)
415 {
416 	short fh, hi, lo;
417 	volatile uint16_t *kf;
418 	uint8_t *f;
419 
420 	hi = ip->save_char & 0x7f;
421 	lo = ch & 0x7f;
422 
423 	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
424 		/* multibyte character */
425 		kf = (volatile uint16_t *)tv_kfont[hi];
426 		kf += lo * FONTHEIGHT;
427 		/* draw plane */
428 		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
429 			*(uint16_t *)p = *kf++;
430 		*(uint16_t *)p = expbits(*kf++);
431 		p += ROWBYTES;
432 		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
433 			*(uint16_t *)p = *kf++;
434 		return;
435 	}
436 
437 	/* singlebyte character */
438 	f = tv_getfont(*ip->GL, ch);
439 
440 	/* draw plane */
441 	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
442 		*p = *f++;
443 	*p = expbits(*f++);
444 	p += ROWBYTES;
445 	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
446 		*p = *f++;
447 }
448 
449 static void
450 tv_putc_bd_in(struct ite_softc *ip, int ch, char *p)
451 {
452 	short fh, hi, lo;
453 	u_int data;
454 	volatile uint16_t *kf;
455 	uint8_t *f;
456 
457 	hi = ip->save_char & 0x7f;
458 	lo = ch & 0x7f;
459 
460 	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
461 		/* multibyte character */
462 		kf = (volatile uint16_t *)tv_kfont[hi];
463 		kf += lo * FONTHEIGHT;
464 		/* draw plane */
465 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
466 			data = *kf++;
467 			*(uint16_t *)p = ~(data | (data >> 1));
468 		}
469 		return;
470 	}
471 
472 	/* singlebyte character */
473 	f = tv_getfont(*ip->GL, ch);
474 
475 	/* draw plane */
476 	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
477 		data = *f++;
478 		*p = ~(data | (data >> 1));
479 	}
480 }
481 
482 static void
483 tv_putc_ul_in(struct ite_softc *ip, int ch, char *p)
484 {
485 	short fh, hi, lo;
486 	volatile uint16_t *kf;
487 	uint8_t *f;
488 
489 	hi = ip->save_char & 0x7f;
490 	lo = ch & 0x7f;
491 
492 	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
493 		/* multibyte character */
494 		kf = (volatile uint16_t *)tv_kfont[hi];
495 		kf += lo * FONTHEIGHT;
496 		/* draw plane */
497 		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
498 			*(uint16_t *)p = ~*kf++;
499 		*(uint16_t *)p = ~expbits(*kf++);
500 		p += ROWBYTES;
501 		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
502 			*(uint16_t *)p = ~*kf++;
503 		return;
504 	}
505 
506 	/* singlebyte character */
507 	f = tv_getfont(*ip->GL, ch);
508 
509 	/* draw plane */
510 	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
511 		*p = ~*f++;
512 	*p = ~expbits(*f++);
513 	p += ROWBYTES;
514 	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
515 		*p = ~*f++;
516 }
517 
518 static void
519 tv_putc_bd_ul(struct ite_softc *ip, int ch, char *p)
520 {
521 	short fh, hi, lo;
522 	u_int data;
523 	volatile uint16_t *kf;
524 	uint8_t *f;
525 
526 	hi = ip->save_char & 0x7f;
527 	lo = ch & 0x7f;
528 
529 	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
530 		/* multibyte character */
531 		kf = (volatile uint16_t *)tv_kfont[hi];
532 		kf += lo * FONTHEIGHT;
533 		/* draw plane */
534 		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
535 			data = *kf++;
536 			*(uint16_t *)p = data | (data >> 1);
537 		}
538 		data = *kf++;
539 		*(uint16_t *)p = expbits(data | (data >> 1));
540 		p += ROWBYTES;
541 		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
542 			data = *kf++;
543 			*(uint16_t *)p = data | (data >> 1);
544 		}
545 		return;
546 	}
547 
548 	/* singlebyte character */
549 	f = tv_getfont(*ip->GL, ch);
550 
551 	/* draw plane */
552 	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
553 		data = *f++;
554 		*p = data | (data >> 1);
555 	}
556 	data = *f++;
557 	*p = expbits(data | (data >> 1));
558 	p += ROWBYTES;
559 	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
560 		data = *f++;
561 		*p = data | (data >> 1);
562 	}
563 }
564 
565 static void
566 tv_putc_bd_ul_in(struct ite_softc *ip, int ch, char *p)
567 {
568 	short fh, hi, lo;
569 	u_int data;
570 	volatile uint16_t *kf;
571 	uint8_t *f;
572 
573 	hi = ip->save_char & 0x7f;
574 	lo = ch & 0x7f;
575 
576 	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
577 		/* multibyte character */
578 		kf = (volatile uint16_t *)tv_kfont[hi];
579 		kf += lo * FONTHEIGHT;
580 		/* draw plane */
581 		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
582 			data = *kf++;
583 			*(uint16_t *)p = ~(data | (data >> 1));
584 		}
585 		data = *kf++;
586 		*(uint16_t *)p = ~expbits(data | (data >> 1));
587 		p += ROWBYTES;
588 		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
589 			data = *kf++;
590 			*(uint16_t *)p = ~(data | (data >> 1));
591 		}
592 		return;
593 	}
594 
595 	/* singlebyte character */
596 	f = tv_getfont(*ip->GL, ch);
597 
598 	/* draw plane */
599 	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
600 		data = *f++;
601 		*p = ~(data | (data >> 1));
602 	}
603 	data = *f++;
604 	*p = ~expbits(data | (data >> 1));
605 	p += ROWBYTES;
606 	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
607 		data = *f++;
608 		data |= data >> 1;
609 		*p = ~(data | (data >> 1));
610 	}
611 }
612 
613 /*
614  * draw/erase/move cursor
615  */
616 static void
617 tv_cursor(struct ite_softc *ip, int flag)
618 {
619 	uint8_t *p;
620 	short fh;
621 
622 	/* erase */
623 	switch (flag) {
624 	/*case DRAW_CURSOR:*/
625 	/*case ERASE_CURSOR:*/
626 	/*case MOVE_CURSOR:*/
627 	case START_CURSOROPT:
628 		/*
629 		 * old: ip->cursorx, ip->cursory
630 		 * new: ip->curx, ip->cury
631 		 */
632 		p = CHADDR(ip->cursory, ip->cursorx);
633 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
634 			*p = ~*p;
635 		break;
636 	}
637 
638 	/* draw */
639 	switch (flag) {
640 	/*case MOVE_CURSOR:*/
641 	case END_CURSOROPT:
642 		/*
643 		 * Use exclusive-or.
644 		 */
645 		p = CHADDR(ip->cury, ip->curx);
646 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
647 			*p = ~*p;
648 
649 		ip->cursorx = ip->curx;
650 		ip->cursory = ip->cury;
651 		break;
652 	}
653 }
654 
655 /*
656  * clear rectangle
657  */
658 static void
659 tv_clear(struct ite_softc *ip, int y, int x, int height, int width)
660 {
661 	uint8_t *p;
662 	short fh;
663 
664 	/* XXX: reset scroll register on clearing whole screen */
665 	if (y == 0 && x == 0 && height == ip->rows && width == ip->cols) {
666 		CRTC.r10 = 0;
667 		CRTC.r11 = tv_top * FONTHEIGHT;
668 	}
669 
670 	CRTC.r21 = 0x01f0;
671 	while (height--) {
672 		p = CHADDR(y++, x);
673 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
674 			memset(p, 0, width);
675 	}
676 	/* crtc mode reset */
677 	CRTC.r21 = 0;
678 }
679 
680 /*
681  * scroll lines/columns
682  */
683 static void
684 tv_scroll(struct ite_softc *ip, int srcy, int srcx, int count, int dir)
685 {
686 	int dst, siz, pl;
687 
688 	switch (dir) {
689 	case SCROLL_UP:
690 		/*
691 		 * src: srcy
692 		 * dst: (srcy - count)
693 		 * siz: (ip->bottom_margin - sy + 1)
694 		 */
695 		dst = srcy - count;
696 		siz = ip->bottom_margin - srcy + 1;
697 		if (dst == 0 && ip->bottom_margin == ip->rows - 1) {
698 			/* special case, hardware scroll */
699 			tv_top = (tv_top + count) % PLANELINES;
700 			CRTC.r11 = tv_top * FONTHEIGHT;
701 		} else {
702 			srcy = PHYSLINE(srcy);
703 			dst = PHYSLINE(dst);
704 			txrascpy(srcy, dst, siz, 0x0f);
705 		}
706 		break;
707 
708 	case SCROLL_DOWN:
709 		/*
710 		 * src: srcy
711 		 * dst: (srcy + count)
712 		 * siz: (ip->bottom_margin - dy + 1)
713 		 */
714 		dst = srcy + count;
715 		siz = ip->bottom_margin - dst + 1;
716 		if (srcy == 0 && ip->bottom_margin == ip->rows - 1) {
717 			/* special case, hardware scroll */
718 			tv_top = (tv_top + PLANELINES - count) % PLANELINES;
719 			CRTC.r11 = tv_top * FONTHEIGHT;
720 		} else {
721 			srcy = PHYSLINE(srcy) + siz - 1;
722 			dst = PHYSLINE(dst) + siz - 1;
723 			txrascpy(srcy, dst, siz, 0x0f | 0x8000);
724 		}
725 		break;
726 
727 	case SCROLL_LEFT:
728 		for (pl = 0; pl < PLANESIZE * 4; pl += PLANESIZE) {
729 			short fh;
730 			uint8_t *src = CHADDR(srcy, srcx) + pl;
731 			uint8_t *dest = CHADDR(srcy, srcx - count) + pl;
732 
733 			siz = ip->cols - srcx;
734 			for (fh = 0; fh < FONTHEIGHT; fh++) {
735 				memcpy(dest, src, siz);
736 				src += ROWBYTES;
737 				dest += ROWBYTES;
738 			}
739 		}
740 		break;
741 
742 	case SCROLL_RIGHT:
743 		for (pl = 0; pl < PLANESIZE * 4; pl += PLANESIZE) {
744 			short fh;
745 			uint8_t *src = CHADDR(srcy, srcx) + pl;
746 			uint8_t *dest = CHADDR(srcy, srcx + count) + pl;
747 
748 			siz = ip->cols - (srcx + count);
749 			for (fh = 0; fh < FONTHEIGHT; fh++) {
750 				memcpy(dest, src, siz);
751 				src += ROWBYTES;
752 				dest += ROWBYTES;
753 			}
754 		}
755 		break;
756 	}
757 }
758 
759 #if defined(ITE_SIXEL)
760 /*
761  * put SIXEL graphics
762  */
763 void
764 tv_sixel(struct ite_softc *ip, int sy, int sx)
765 {
766 	uint8_t *p;
767 	int width;
768 	int y;
769 	int cx;
770 	int px;
771 	uint16_t data[3];
772 	uint8_t color;
773 
774 	width = MIN(ip->decsixel_ph, MAX_SIXEL_WIDTH);
775 	width = MIN(width, PLANEWIDTH - sx * FONTWIDTH);
776 
777 	p = CHADDR(sy, sx);
778 	p += ROWBYTES * ip->decsixel_y;
779 	/* boundary check */
780 	if (p < tv_row[0]) {
781 		p = tv_end + (p - tv_row[0]);
782 	}
783 
784 	for (y = 0; y < 6; y++) {
785 		/* for each 16dot word */
786 		for (cx = 0; cx < howmany(width, 16); cx++) {
787 			data[0] = 0;
788 			data[1] = 0;
789 			data[2] = 0;
790 			for (px = 0; px < 16; px++) {
791 				color = ip->decsixel_buf[cx * 16 + px] >> (y * 4);
792 				/* x68k console is 8 colors */
793 				data[0] = (data[0] << 1) | ((color >> 0) & 1);
794 				data[1] = (data[1] << 1) | ((color >> 1) & 1);
795 				data[2] = (data[2] << 1) | ((color >> 2) & 1);
796 			}
797 			*(uint16_t *)(p + cx * 2          ) = data[0];
798 			*(uint16_t *)(p + cx * 2 + 0x20000) = data[1];
799 			*(uint16_t *)(p + cx * 2 + 0x40000) = data[2];
800 		}
801 
802 		p += ROWBYTES;
803 		if (p >= tv_end) {
804 			p = tv_row[0] + (p - tv_end);
805 		}
806 	}
807 }
808 #endif /* ITE_SIXEL */
809