Home | History | Annotate | Line # | Download | only in dev
      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