Module Name: src Committed By: isaki Date: Sat Oct 5 03:56:54 UTC 2024
Modified Files: src/sys/arch/x68k/conf: GENERIC files.x68k src/sys/arch/x68k/dev: ite.c ite_tv.c itevar.h Log Message: x68k: Add SIXEL graphics sequence support. - The palette definition is fixed to the same color as the text (currently, it's RGB 8 colors). Any palette definition sent will be ignored. - Aspect ratio and bg color mode is not supported (yet). - An OR mode is supported. This is proposed by Y.Sugahara in this implementation and then the mlterm also supports it. It's an advantageous way for the multi plane color VRAM. - ITE_SIXEL kernel option is added and is disabled by default for now. It was first written by me in 2014 and has been demonstrated in Open Source Conference Hiroshima every year since then. In this year, it's also demonstrated on real X68030 at Japan NetBSD Users Group booth in OSC 2024 Hiroshima, last week. https://x.com/OSC_official/status/1841381234804498608 It's useful for showing and explaining about the possibility of NetBSD and old machines for younger (than X68030) engineers or students. To generate a diff of this commit: cvs rdiff -u -r1.209 -r1.210 src/sys/arch/x68k/conf/GENERIC cvs rdiff -u -r1.84 -r1.85 src/sys/arch/x68k/conf/files.x68k cvs rdiff -u -r1.71 -r1.72 src/sys/arch/x68k/dev/ite.c cvs rdiff -u -r1.20 -r1.21 src/sys/arch/x68k/dev/ite_tv.c cvs rdiff -u -r1.17 -r1.18 src/sys/arch/x68k/dev/itevar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/x68k/conf/GENERIC diff -u src/sys/arch/x68k/conf/GENERIC:1.209 src/sys/arch/x68k/conf/GENERIC:1.210 --- src/sys/arch/x68k/conf/GENERIC:1.209 Sun Jan 7 07:58:33 2024 +++ src/sys/arch/x68k/conf/GENERIC Sat Oct 5 03:56:54 2024 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.209 2024/01/07 07:58:33 isaki Exp $ +# $NetBSD: GENERIC,v 1.210 2024/10/05 03:56:54 isaki Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/x68k/conf/std.x68k" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.209 $" +#ident "GENERIC-$Revision: 1.210 $" makeoptions COPTS="-O2 -fno-reorder-blocks -fno-unwind-tables -fno-omit-frame-pointer" # See share/mk/sys.mk. -fno-omit-frame-pointer is necessary for @@ -229,6 +229,7 @@ kbd0 at mfp0 # standard keyboard ite0 at grf0 grfaddr 0 # internal terminal emulator options ITE_KERNEL_ATTR=4 # bold for kernel messages # see /sys/arch/x68k/dev/itevar.h +#options ITE_SIXEL ## floppy disks fdc0 at intio0 addr 0xe94000 intr 96 dma 0 dmaintr 100 # floppy controller Index: src/sys/arch/x68k/conf/files.x68k diff -u src/sys/arch/x68k/conf/files.x68k:1.84 src/sys/arch/x68k/conf/files.x68k:1.85 --- src/sys/arch/x68k/conf/files.x68k:1.84 Tue Jan 9 04:16:27 2024 +++ src/sys/arch/x68k/conf/files.x68k Sat Oct 5 03:56:54 2024 @@ -1,4 +1,4 @@ -# $NetBSD: files.x68k,v 1.84 2024/01/09 04:16:27 thorpej Exp $ +# $NetBSD: files.x68k,v 1.85 2024/10/05 03:56:54 isaki Exp $ # # new style config file for x68k architecture # @@ -68,6 +68,7 @@ file arch/x68k/dev/grf_tv.c grf | ite file arch/x68k/dev/grf_gv.c grf | ite defparam opt_ite.h ITE_KERNEL_ATTR +defflag opt_ite.h ITE_SIXEL device ite : tty attach ite at grf file arch/x68k/dev/ite.c ite needs-flag Index: src/sys/arch/x68k/dev/ite.c diff -u src/sys/arch/x68k/dev/ite.c:1.71 src/sys/arch/x68k/dev/ite.c:1.72 --- src/sys/arch/x68k/dev/ite.c:1.71 Sun Jan 7 07:58:33 2024 +++ src/sys/arch/x68k/dev/ite.c Sat Oct 5 03:56:54 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: ite.c,v 1.71 2024/01/07 07:58:33 isaki Exp $ */ +/* $NetBSD: ite.c,v 1.72 2024/10/05 03:56:54 isaki Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -45,7 +45,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ite.c,v 1.71 2024/01/07 07:58:33 isaki Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ite.c,v 1.72 2024/10/05 03:56:54 isaki Exp $"); #include "ite.h" #if NITE > 0 @@ -91,6 +91,9 @@ void opm_bell(void); #define SUBR_CLEAR(ip,sy,sx,h,w) ip->isw->ite_clear(ip,sy,sx,h,w) #define SUBR_SCROLL(ip,sy,sx,count,dir) \ ip->isw->ite_scroll(ip,sy,sx,count,dir) +#if defined(ITE_SIXEL) +#define SUBR_SIXEL(ip,sy,sx) ip->isw->ite_sixel(ip,sy,sx) +#endif struct consdev; @@ -151,6 +154,9 @@ static u_char cons_tabs[MAX_TABS]; static void itestart(struct tty *); static void iteputchar(int, struct ite_softc *); +#if defined(ITE_SIXEL) +static int ite_dcs(const int, struct ite_softc *); +#endif static void ite_putstr(const u_char *, int, dev_t); static int itematch(device_t, cfdata_t, void *); @@ -1207,10 +1213,18 @@ ite_putstr(const u_char *s, int len, dev if ((ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) return; +#if defined(ITE_SIXEL) + /* avoid flicking cursor */ + if (ip->escape == 0) +#endif SUBR_CURSOR(ip, START_CURSOROPT); for (i = 0; i < len; i++) if (s[i] != 0) iteputchar(s[i], ip); +#if defined(ITE_SIXEL) + /* avoid flicking cursor */ + if (ip->escape == 0) +#endif SUBR_CURSOR(ip, END_CURSOROPT); } @@ -1220,7 +1234,11 @@ iteputchar(int c, struct ite_softc *ip) int n, x, y; char *cp; +#if defined(ITE_SIXEL) + if ((c >= 0x20 && ip->escape != 0) || ip->escape == DCS) { +#else if (c >= 0x20 && ip->escape != 0) { +#endif switch (ip->escape) { case ESC: @@ -1284,6 +1302,11 @@ iteputchar(int c, struct ite_softc *ip) /* String Terminator */ c = ST; ip->escape = 0; +#if defined(ITE_SIXEL) + if (ip->decsixel_y != 0) { + ite_lf(ip); + } +#endif break; case ']': @@ -1613,8 +1636,13 @@ iteputchar(int c, struct ite_softc *ip) ite_sendstr(ip, "\033[?1;1c"); else +#if defined(ITE_SIXEL) + ite_sendstr(ip, + "\033[63;4c"); +#else ite_sendstr(ip, "\033[63;0c"); +#endif break; } } @@ -2162,6 +2190,14 @@ iteputchar(int c, struct ite_softc *ip) } break; +#if defined(ITE_SIXEL) + case DCS: + if (ite_dcs(c, ip) == 0) { + return; + } + break; +#endif /* ITE_SIXEL */ + default: ip->escape = 0; return; @@ -2289,6 +2325,9 @@ iteputchar(int c, struct ite_softc *ip) case DCS: /* device control string introducer */ ip->escape = DCS; +#if defined(ITE_SIXEL) + ip->dcs_cmd = DCS_START; +#endif ip->ap = ip->argbuf; break; @@ -2355,6 +2394,306 @@ iteputchar(int c, struct ite_softc *ip) } } +#if defined(ITE_SIXEL) +/* + * Handle DCS. + * 0: return in the caller. + * !0: break the switch-case in the caller. + */ +static int +ite_dcs(const int c, struct ite_softc *ip) +{ + static const uint32_t table[64] = { + 0x000000, 0x000001, 0x000010, 0x000011, + 0x000100, 0x000101, 0x000110, 0x000111, + 0x001000, 0x001001, 0x001010, 0x001011, + 0x001100, 0x001101, 0x001110, 0x001111, + 0x010000, 0x010001, 0x010010, 0x010011, + 0x010100, 0x010101, 0x010110, 0x010111, + 0x011000, 0x011001, 0x011010, 0x011011, + 0x011100, 0x011101, 0x011110, 0x011111, + 0x100000, 0x100001, 0x100010, 0x100011, + 0x100100, 0x100101, 0x100110, 0x100111, + 0x101000, 0x101001, 0x101010, 0x101011, + 0x101100, 0x101101, 0x101110, 0x101111, + 0x110000, 0x110001, 0x110010, 0x110011, + 0x110100, 0x110101, 0x110110, 0x110111, + 0x111000, 0x111001, 0x111010, 0x111011, + 0x111100, 0x111101, 0x111110, 0x111111, + }; + + switch (ip->dcs_cmd) { + case DCS_DISCARD: + /* discard sixel cause kernel message interrupted */ + switch (c) { + case '-': + /* restart from next SIXEL line */ + ite_lf(ip); + goto sixel_restart; + + case CAN: + case SUB: + /* SUB should also display a reverse question mark... */ + ip->escape = 0; + return 0; + + case ESC: + ip->escape = ESC; + return 0; + + default: + return 0; + } + break; + + case DCS_START: + /* the biggie... */ + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ';': + case '$': + if (ip->ap < ip->argbuf + MAX_ARGSIZE) + *ip->ap++ = c; + return 0; + + case 'q': + { + char *cp; + + /* init sixel */ + /* + * DCS <P1> ; <P2> ; <P3> q + * P1 is aspect ratio, XXX not supported. + * P2 is bgcolor mode. + * 0..2: bgcolor mode, XXX not supported here. + * bit2 means 'OR'ed color mode. + * This is an original extension. + */ + ip->ap = ip->argbuf; + cp = strchr(ip->ap, ';'); + if (cp != NULL) { + int mode; + mode = atoi(cp + 1) - '0'; + ip->decsixel_ormode = (mode & 4); + } else { + ip->decsixel_ormode = 0; + } +sixel_restart: + ip->dcs_cmd = DCS_SIXEL; + ip->decsixel_state = DECSIXEL_INIT; + ip->decsixel_ph = MAX_SIXEL_WIDTH; + ip->decsixel_x = 0; + ip->decsixel_y = 0; + ip->decsixel_repcount = 0; + ip->decsixel_color = ip->fgcolor; + memset(ip->decsixel_buf, 0, sizeof(ip->decsixel_buf)); + return 0; + } + + case CAN: + case SUB: + /* SUB should also display a reverse question mark... */ + ip->escape = 0; + return 0; + + case ESC: + ip->escape = ESC; + return 0; + + default: + return 0; + } + break; + + case DCS_SIXEL: +sixel_loop: + switch (ip->decsixel_state) { + case DECSIXEL_INIT: + switch (c) { + case CAN: + case SUB: + /* + * SUB should also display a reverse question + * mark... + */ + ip->escape = 0; + return 0; + + case ESC: + ip->escape = ESC; + return 0; + + case DECSIXEL_REPEAT: + ip->decsixel_state = c; + ip->decsixel_repcount = 0; + return 0; + + case DECSIXEL_RASTER: + case DECSIXEL_COLOR: + ip->decsixel_state = c; + ip->ap = ip->argbuf; + return 0; + + case '$': /* CR */ + ip->decsixel_x = 0; + return 0; + + case '-': /* LF */ + /* + * XXX + * FONTHEIGHT is defined in ite_tv.c, not here.. + */ + if (ip->decsixel_y + 6 > 15) { + ite_lf(ip); + ip->decsixel_y -= 16; + } + SUBR_SIXEL(ip, ip->cury, ip->curx); + memset(ip->decsixel_buf, 0, + sizeof(ip->decsixel_buf)); + ip->decsixel_x = 0; + ip->decsixel_y += 6; + return 0; + + default: + if ('?' <= c && c <= '~' + && ip->decsixel_x < MAX_SIXEL_WIDTH) { + uint32_t d; + d = table[c - '?'] * ip->decsixel_color; + ip->decsixel_buf[ip->decsixel_x] |= d; + ip->decsixel_x++; + } else { + /* ignore */ + } + return 0; + } + break; + + case DECSIXEL_REPEAT: + if ('0' <= c && c <= '9') { + ip->decsixel_repcount = + ip->decsixel_repcount * 10 + (c - '0'); + } else if ('?' <= c && c <= '~') { + uint32_t d; + int i; + int cnt = MIN(ip->decsixel_repcount, + MAX_SIXEL_WIDTH - ip->decsixel_x); + d = table[c - '?'] * ip->decsixel_color; + for (i = 0; i < cnt; i++) { + ip->decsixel_buf[ip->decsixel_x + i] |= + d; + } + ip->decsixel_x += cnt; + ip->decsixel_state = DECSIXEL_INIT; + } else { + /* invalid ? */ + ip->decsixel_state = DECSIXEL_INIT; + } + return 0; + + case DECSIXEL_RASTER: + case DECSIXEL_RASTER_PAD: + case DECSIXEL_RASTER_PH: + case DECSIXEL_RASTER_PV: + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (ip->ap < ip->argbuf + MAX_ARGSIZE) + *ip->ap++ = c; + return 0; + + case ';': + default: + switch (ip->decsixel_state) { + case DECSIXEL_RASTER: + /* ignore PAN */ + ip->ap = ip->argbuf; + ip->decsixel_state = + DECSIXEL_RASTER_PAD; + return 0; + + case DECSIXEL_RASTER_PAD: + /* ignore PAD */ + ip->ap = ip->argbuf; + ip->decsixel_state = DECSIXEL_RASTER_PH; + return 0; + + case DECSIXEL_RASTER_PH: + ip->decsixel_ph = ite_zargnum(ip); + ip->ap = ip->argbuf; + ip->decsixel_state = DECSIXEL_RASTER_PV; + return 0; + + case DECSIXEL_RASTER_PV: + /* ignore PV */ + ip->decsixel_state = DECSIXEL_INIT; + /* c is a next sequence char. */ + goto sixel_loop; + + default: + /* NOTREACHED */ + return 0; + } + } + return 0; + + case DECSIXEL_COLOR: + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ';': + if (ip->ap < ip->argbuf + MAX_ARGSIZE) + *ip->ap++ = c; + return 0; + + default: + *ip->ap = '\0'; + if (strchr(ip->argbuf, ';')) { + /* ignore the palette definition. */ + } else { + /* otherwise, it specifies color. */ + ip->decsixel_color = + ite_zargnum(ip) & 7; + } + ip->decsixel_state = DECSIXEL_INIT; + ip->ap = ip->argbuf; + /* c is a next sequence char. */ + goto sixel_loop; + } + return 0; + } + break; + } + + /* Continue in caller's switch-case. */ + return 1; +} +#endif /* ITE_SIXEL */ + static void iteprecheckwrap(struct ite_softc *ip) { @@ -2547,12 +2886,23 @@ itecnputc(dev_t dev, int c) #ifdef ITE_KERNEL_ATTR short save_attribute; #endif +#if defined(ITE_SIXEL) + int save_escape; +#endif if (panicstr && !paniced && (ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) { (void) iteon(dev, 3); paniced = 1; } + +#if defined(ITE_SIXEL) + save_escape = ip->escape; + if (ip->escape == DCS) { + ip->escape = 0; + ip->dcs_cmd = DCS_DISCARD; + } +#endif #ifdef ITE_KERNEL_ATTR save_attribute = ip->attribute; ip->attribute = ITE_KERNEL_ATTR; @@ -2561,5 +2911,10 @@ itecnputc(dev_t dev, int c) #ifdef ITE_KERNEL_ATTR ip->attribute = save_attribute; #endif +#if defined(ITE_SIXEL) + if (ip->escape == 0) { + ip->escape = save_escape; + } +#endif } #endif Index: src/sys/arch/x68k/dev/ite_tv.c diff -u src/sys/arch/x68k/dev/ite_tv.c:1.20 src/sys/arch/x68k/dev/ite_tv.c:1.21 --- src/sys/arch/x68k/dev/ite_tv.c:1.20 Sun Jan 7 07:58:33 2024 +++ src/sys/arch/x68k/dev/ite_tv.c Sat Oct 5 03:56:54 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: ite_tv.c,v 1.20 2024/01/07 07:58:33 isaki Exp $ */ +/* $NetBSD: ite_tv.c,v 1.21 2024/10/05 03:56:54 isaki Exp $ */ /* * Copyright (c) 1997 Masaru Oki. @@ -31,7 +31,9 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ite_tv.c,v 1.20 2024/01/07 07:58:33 isaki Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ite_tv.c,v 1.21 2024/10/05 03:56:54 isaki Exp $"); + +#include "opt_ite.h" #include <sys/param.h> #include <sys/device.h> @@ -71,6 +73,9 @@ __KERNEL_RCSID(0, "$NetBSD: ite_tv.c,v 1 static u_int tv_top; static uint8_t *tv_row[PLANELINES]; +#if defined(ITE_SIXEL) +static uint8_t *tv_end; +#endif static uint8_t *tv_font[256]; static volatile uint8_t *tv_kfont[0x7f]; @@ -89,6 +94,9 @@ static void tv_putc(struct ite_softc *, static void tv_cursor(struct ite_softc *, int); static void tv_clear(struct ite_softc *, int, int, int, int); static void tv_scroll(struct ite_softc *, int, int, int, int); +#if defined(ITE_SIXEL) +static void tv_sixel(struct ite_softc *, int, int); +#endif static inline uint32_t expbits(uint32_t); static inline void txrascpy(uint8_t, uint8_t, int16_t, uint16_t); @@ -166,6 +174,9 @@ tv_init(struct ite_softc *ip) for (i = 0; i < PLANELINES; i++) tv_row[i] = (void *)__UNVOLATILE(&IODEVbase->tvram[ROWOFFSET(i)]); +#if defined(ITE_SIXEL) + tv_end = (void *)__UNVOLATILE(&IODEVbase->tvram[ROWOFFSET(i)]); +#endif /* shadow ANK font */ memcpy(kern_font, (void *)&IODEVbase->cgrom0_8x16, 256 * FONTHEIGHT); ite_set_glyph(); @@ -189,6 +200,9 @@ tv_init(struct ite_softc *ip) ip->isw->ite_cursor = tv_cursor; ip->isw->ite_clear = tv_clear; ip->isw->ite_scroll = tv_scroll; +#if defined(ITE_SIXEL) + ip->isw->ite_sixel = tv_sixel; +#endif /* * Initialize colormap @@ -741,3 +755,54 @@ tv_scroll(struct ite_softc *ip, int srcy break; } } + +#if defined(ITE_SIXEL) +/* + * put SIXEL graphics + */ +void +tv_sixel(struct ite_softc *ip, int sy, int sx) +{ + uint8_t *p; + int width; + int y; + int cx; + int px; + uint16_t data[3]; + uint8_t color; + + width = MIN(ip->decsixel_ph, MAX_SIXEL_WIDTH); + width = MIN(width, PLANEWIDTH - sx * FONTWIDTH); + + p = CHADDR(sy, sx); + p += ROWBYTES * ip->decsixel_y; + /* boundary check */ + if (p < tv_row[0]) { + p = tv_end + (p - tv_row[0]); + } + + for (y = 0; y < 6; y++) { + /* for each 16dot word */ + for (cx = 0; cx < howmany(width, 16); cx++) { + data[0] = 0; + data[1] = 0; + data[2] = 0; + for (px = 0; px < 16; px++) { + color = ip->decsixel_buf[cx * 16 + px] >> (y * 4); + /* x68k console is 8 colors */ + data[0] = (data[0] << 1) | ((color >> 0) & 1); + data[1] = (data[1] << 1) | ((color >> 1) & 1); + data[2] = (data[2] << 1) | ((color >> 2) & 1); + } + *(uint16_t *)(p + cx * 2 ) = data[0]; + *(uint16_t *)(p + cx * 2 + 0x20000) = data[1]; + *(uint16_t *)(p + cx * 2 + 0x40000) = data[2]; + } + + p += ROWBYTES; + if (p >= tv_end) { + p = tv_row[0] + (p - tv_end); + } + } +} +#endif /* ITE_SIXEL */ Index: src/sys/arch/x68k/dev/itevar.h diff -u src/sys/arch/x68k/dev/itevar.h:1.17 src/sys/arch/x68k/dev/itevar.h:1.18 --- src/sys/arch/x68k/dev/itevar.h:1.17 Sun Jan 7 07:58:33 2024 +++ src/sys/arch/x68k/dev/itevar.h Sat Oct 5 03:56:54 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: itevar.h,v 1.17 2024/01/07 07:58:33 isaki Exp $ */ +/* $NetBSD: itevar.h,v 1.18 2024/10/05 03:56:54 isaki Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -50,6 +50,7 @@ struct itesw { void (*ite_putc)(struct ite_softc *, int, int, int, int); void (*ite_cursor)(struct ite_softc *, int); void (*ite_scroll)(struct ite_softc *, int, int, int, int); + void (*ite_sixel)(struct ite_softc *, int, int); }; enum ite_arraymaxs { @@ -94,6 +95,28 @@ struct ite_softc { short save_curx, save_cury, save_attribute, save_char; char sc_G0, sc_G1, sc_G2, sc_G3; char *sc_GL, *sc_GR; + enum { + DCS_START = 0, + DCS_SIXEL = 'q', /* DECRQSS also use 'q'... */ + DCS_DISCARD = -1, + } dcs_cmd; + enum { + DECSIXEL_INIT = 0, + DECSIXEL_RASTER_PAD, + DECSIXEL_RASTER_PH, + DECSIXEL_RASTER_PV, + DECSIXEL_REPEAT = '!', + DECSIXEL_RASTER = '\"', + DECSIXEL_COLOR = '#', + } decsixel_state; + int decsixel_ph; + int decsixel_x; + int decsixel_y; + int decsixel_repcount; + int decsixel_color; + int decsixel_ormode; +#define MAX_SIXEL_WIDTH (768) + uint32_t decsixel_buf[MAX_SIXEL_WIDTH]; }; enum emul_level {