#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: omrasops.c,v 1.27 2024/09/20 03:24:05 isaki Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <arch/luna68k/dev/omrasopsvar.h>
#ifdef luna68k
#define USE_M68K_ASM 1
#endif
#if defined(__GNUC__)
#define ASSUME(cond) if (!(cond)) __unreachable()
#elif defined(__clang__) && __has_builtin(__builtin_assume)
#define ASSUME(cond) __builtin_assume(cond)
#else
#define ASSUME(cond) (void)(cond)
#endif
typedef struct {
union {
int32_t all;
struct {
int8_t ismulti;
uint8_t fg;
uint8_t bg;
uint8_t reserved;
};
};
} rowattr_t;
static void om_cursor(void *, int, int, int);
static int om_mapchar(void *, int, u_int *);
static void om_putchar(void *, int, int, u_int, long);
static void om1_copycols(void *, int, int, int, int);
static void om4_copycols(void *, int, int, int, int);
static void om1_copyrows(void *, int, int, int num);
static void om4_copyrows(void *, int, int, int num);
static void om_erasecols(void *, int, int, int, long);
static void om_eraserows(void *, int, int, long);
static int om_allocattr(void *, int, int, int, long *);
static void om_fill(int, int, uint8_t *, int, int, uint32_t, int, int);
static void om_fill_color(int, int, uint8_t *, int, int, int, int);
static void om_rascopy_single(int, uint8_t *, uint8_t *, int16_t, int16_t,
uint8_t[]);
static void om4_rascopy_multi(uint8_t *, uint8_t *, int16_t, int16_t);
static void om_unpack_attr(long, uint8_t *, uint8_t *, int *);
static int omrasops_init(struct rasops_info *, int, int);
#define OMRASOPS_MAX_ROWS 43
static rowattr_t rowattr[OMRASOPS_MAX_ROWS];
#define ALL1BITS (~0U)
#define ALL0BITS (0U)
#define BLITWIDTH (32)
#define ALIGNMASK (0x1f)
#define BYTESDONE (4)
#if 0
#define OMFB_ATTR_MULTICOLOR (1U << 31)
#define OMFB_ATTR_UNDERLINE (1U << 17)
#define OMFB_ATTR_BOLD (1U << 16)
#endif
#define P0(addr) ((uint32_t *)((uint8_t *)(addr) + OMFB_PLANEOFFS * 1))
#define P1(addr) ((uint32_t *)((uint8_t *)(addr) + OMFB_PLANEOFFS * 2))
#define P2(addr) ((uint32_t *)((uint8_t *)(addr) + OMFB_PLANEOFFS * 3))
#define P3(addr) ((uint32_t *)((uint8_t *)(addr) + OMFB_PLANEOFFS * 4))
#define FASTGETBITS(psrc, x, w, dst) \
asm("bfextu %3{%1:%2},%0" \
: "=d" (dst) \
: "di" (x), "di" (w), "o" (*(uint32_t *)(psrc)))
#define FASTPUTBITS(src, x, w, pdst) \
asm("bfins %3,%0{%1:%2}" \
: "+o" (*(uint32_t *)(pdst)) \
: "di" (x), "di" (w), "d" (src) \
: "memory" )
#define GETBITS(psrc, x, w, dst) FASTGETBITS(psrc, x, w, dst)
#define PUTBITS(src, x, w, pdst) FASTPUTBITS(src, x, w, pdst)
#if USE_M68K_ASM
#define CLEAR_LOWER_BITS(x, w) \
asm volatile( \
" bclr %[width],%[data] ;\n" \
" addq.l #1,%[data] ;\n" \
: [data] "+&d" (x) \
: [width] "d" (w) \
: \
)
#else
#define CLEAR_LOWER_BITS(x, w) x = ((x) & ~(1U << (w))) + 1
#endif
static inline void
om_set_planemask(int planemask)
{
*(volatile uint32_t *)OMFB_PLANEMASK = planemask;
}
static inline volatile uint32_t *
om_rop_addr(int plane, int rop)
{
return (volatile uint32_t *)
(OMFB_ROP_P0 + OMFB_PLANEOFFS * plane + rop * 4);
}
static inline void
om_set_rop(int plane, int rop, uint32_t mask)
{
*om_rop_addr(plane, rop) = mask;
}
static inline void
om_set_rop_curplane(int rop, uint32_t mask)
{
((volatile uint32_t *)(OMFB_ROP_COMMON))[rop] = mask;
}
static inline void
om_reset_planemask_and_rop(void)
{
om_set_planemask(hwplanemask);
om_set_rop_curplane(ROP_THROUGH, ~0U);
}
static inline void
om_set_rowattr(int row, uint8_t fg, uint8_t bg)
{
if (rowattr[row].fg == fg && rowattr[row].bg == bg)
return;
if (rowattr[row].ismulti)
return;
if (rowattr[row].fg == rowattr[row].bg) {
if (rowattr[row].fg != fg && rowattr[row].bg != bg) {
rowattr[row].ismulti = true;
} else {
rowattr[row].fg = fg;
rowattr[row].bg = bg;
}
} else {
rowattr[row].ismulti = true;
}
}
static inline void
om_reset_rowattr(int row, uint8_t bg)
{
rowattr[row].ismulti = false;
rowattr[row].bg = bg;
rowattr[row].fg = bg;
}
static void
om_fill(int planemask, int rop, uint8_t *dstptr, int dstbitoffs, int dstspan,
uint32_t val, int width, int height)
{
uint32_t mask;
uint32_t prev_mask;
int32_t height_m1;
int dw;
ASSUME(width > 0);
ASSUME(height > 0);
ASSUME(0 <= dstbitoffs && dstbitoffs < 32);
om_set_planemask(planemask);
height_m1 = height - 1;
mask = ALL1BITS >> dstbitoffs;
prev_mask = ~mask;
dw = 32 - dstbitoffs;
do {
uint8_t *d;
int32_t h;
width -= dw;
if (width < 0) {
CLEAR_LOWER_BITS(mask, -width);
width = 0;
}
if (prev_mask != mask) {
om_set_rop_curplane(rop, mask);
prev_mask = mask;
}
d = dstptr;
dstptr += 4;
h = height_m1;
#if USE_M68K_ASM
asm volatile("\n"
"om_fill_loop_h:\n"
" move.l %[val],(%[d]) ;\n"
" add.l %[dstspan],%[d] ;\n"
" dbra %[h],om_fill_loop_h ;\n"
:
[d] "+&a" (d),
[h] "+&d" (h)
:
[val] "d" (val),
[dstspan] "r" (dstspan)
:
"memory"
);
#else
do {
*(uint32_t *)d = val;
d += dstspan;
} while (--h >= 0);
#endif
mask = ALL1BITS;
dw = 32;
} while (width > 0);
}
static void
om_fill_color(int planecount, int color, uint8_t *dstptr, int dstbitoffs,
int dstspan, int width, int height)
{
uint32_t mask;
uint32_t prev_mask;
int32_t height_m1;
int dw;
ASSUME(width > 0);
ASSUME(height > 0);
ASSUME(planecount > 0);
om_set_planemask(hwplanemask);
mask = ALL1BITS >> dstbitoffs;
prev_mask = ~mask;
dw = 32 - dstbitoffs;
height_m1 = height - 1;
do {
uint8_t *d;
int32_t plane;
int32_t h;
int16_t rop;
width -= dw;
if (width < 0) {
CLEAR_LOWER_BITS(mask, -width);
width = 0;
}
if (prev_mask != mask) {
for (plane = 0; plane < planecount; plane++) {
if ((color & (1U << plane)) != 0)
rop = ROP_ONE;
else
rop = ROP_ZERO;
om_set_rop(plane, rop, mask);
}
prev_mask = mask;
}
d = dstptr;
dstptr += 4;
h = height_m1;
#if USE_M68K_ASM
asm volatile("\n"
"om_fill_color_loop_h:\n"
" clr.l (%[d]) ;\n"
" add.l %[dstspan],%[d] ;\n"
" dbra %[h],om_fill_color_loop_h ;\n"
:
[d] "+&a" (d),
[h] "+&d" (h)
:
[dstspan] "r" (dstspan)
:
"memory"
);
#else
do {
*(uint32_t *)d = 0;
d += dstspan;
} while (--h >= 0);
#endif
mask = ALL1BITS;
dw = 32;
} while (width > 0);
}
static inline int
om_fgbg2rop(uint8_t fg, uint8_t bg)
{
int t;
t = (bg & 1) * 2 + (fg & 1);
return t * 5;
}
static void
om_putchar(void *cookie, int row, int startcol, u_int uc, long attr)
{
struct rasops_info *ri = cookie;
uint8_t *fontptr;
uint8_t *dstcmn;
uint32_t mask;
int width;
int height;
int planecount;
int x, y;
int fontstride;
int fontx;
int plane;
int dw;
int xh, xl;
uint8_t fg, bg;
static volatile uint32_t *ropaddr[OMFB_MAX_PLANECOUNT];
static uint8_t last_fg, last_bg;
if (uc >= 0x80)
return;
width = ri->ri_font->fontwidth;
height = ri->ri_font->fontheight;
planecount = ri->ri_depth;
fontstride = ri->ri_font->stride;
y = height * row;
x = width * startcol;
fontptr = (uint8_t *)ri->ri_font->data +
(uc - ri->ri_font->firstchar) * ri->ri_fontscale;
om_unpack_attr(attr, &fg, &bg, NULL);
om_set_rowattr(row, fg, bg);
if (last_fg != fg || last_bg != bg) {
last_fg = fg;
last_bg = bg;
for (plane = 0; plane < planecount; plane++) {
int t = om_fgbg2rop(fg, bg);
ropaddr[plane] = om_rop_addr(plane, t);
fg >>= 1;
bg >>= 1;
}
}
xh = x >> 5;
xl = x & 0x1f;
dstcmn = (uint8_t *)ri->ri_bits + xh * 4 + y * OMFB_STRIDE;
om_set_planemask(hwplanemask);
fontx = 0;
mask = ALL1BITS >> xl;
dw = 32 - xl;
ASSUME(planecount == 1 ||
planecount == 4 ||
planecount == 8);
do {
uint8_t *d;
uint8_t *f;
int32_t h;
width -= dw;
if (width < 0) {
CLEAR_LOWER_BITS(mask, -width);
width = 0;
}
switch (planecount) {
case 8:
*(ropaddr[7]) = mask;
*(ropaddr[6]) = mask;
*(ropaddr[5]) = mask;
*(ropaddr[4]) = mask;
case 4:
*(ropaddr[3]) = mask;
*(ropaddr[2]) = mask;
*(ropaddr[1]) = mask;
case 1:
*(ropaddr[0]) = mask;
break;
}
d = dstcmn;
f = fontptr;
h = height - 1;
do {
uint32_t v;
GETBITS(f, fontx, dw, v);
*(uint32_t *)d = v;
d += OMFB_STRIDE;
f += fontstride;
} while (--h >= 0);
dstcmn += 4;
fontx += dw;
mask = ALL1BITS;
dw = 32;
} while (width > 0);
om_reset_planemask_and_rop();
}
static void
om_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
{
struct rasops_info *ri = cookie;
int startx;
int width;
int height;
int planecount;
int sh, sl;
int y;
int scanspan;
uint8_t *p;
uint8_t fg, bg;
scanspan = ri->ri_stride;
y = ri->ri_font->fontheight * row;
startx = ri->ri_font->fontwidth * startcol;
width = ri->ri_font->fontwidth * ncols;
height = ri->ri_font->fontheight;
planecount = ri->ri_depth;
om_unpack_attr(attr, &fg, &bg, NULL);
sh = startx >> 5;
sl = startx & 0x1f;
p = (uint8_t *)ri->ri_bits + y * scanspan + sh * 4;
om_set_rowattr(row, fg, bg);
if (bg == 0) {
om_fill(hwplanemask, ROP_ZERO,
p, sl, scanspan, 0, width, height);
} else {
om_fill_color(planecount, bg, p, sl, scanspan, width, height);
}
om_reset_planemask_and_rop();
}
static void
om_eraserows(void *cookie, int startrow, int nrows, long attr)
{
struct rasops_info *ri = cookie;
int startx;
int width;
int height;
int planecount;
int sh, sl;
int y;
int scanspan;
int row;
uint8_t *p;
uint8_t fg, bg;
scanspan = ri->ri_stride;
y = ri->ri_font->fontheight * startrow;
startx = 0;
width = ri->ri_emuwidth;
height = ri->ri_font->fontheight * nrows;
planecount = ri->ri_depth;
om_unpack_attr(attr, &fg, &bg, NULL);
sh = startx >> 5;
sl = startx & 0x1f;
p = (uint8_t *)ri->ri_bits + y * scanspan + sh * 4;
for (row = startrow; row < startrow + nrows; row++) {
om_reset_rowattr(row, bg);
}
if (bg == 0) {
om_fill(hwplanemask, ROP_ZERO,
p, sl, scanspan, 0, width, height);
} else {
om_fill_color(planecount, bg, p, sl, scanspan, width, height);
}
om_reset_planemask_and_rop();
}
static void
om_rascopy_single(int planecount, uint8_t *dst, uint8_t *src,
int16_t width, int16_t height, uint8_t rop[])
{
uint32_t mask;
int wh;
int wl;
int step;
int plane;
int16_t height_m1;
int16_t w, h;
step = OMFB_STRIDE;
if (height < 0) {
step = -step;
height = -height;
}
height_m1 = height - 1;
wh = (width >> 6);
if (wh > 0) {
int step8 = step - wh * 8;
#if USE_M68K_ASM
wh--;
h = height_m1;
asm volatile("\n"
"om_rascopy_single_LL:\n"
" move.w %[wh],%[w] ;\n"
"1:\n"
" move.l (%[src])+,(%[dst])+ ;\n"
" move.l (%[src])+,(%[dst])+ ;\n"
" dbra %[w],1b ;\n"
" adda.l %[step8],%[src] ;\n"
" adda.l %[step8],%[dst] ;\n"
" dbra %[h],om_rascopy_single_LL ;\n"
:
[src] "+&a" (src),
[dst] "+&a" (dst),
[h] "+&d" (h),
[w] "=&d" (w)
:
[wh] "r" (wh),
[step8] "r" (step8)
:
"memory"
);
#else
wh--;
for (h = height_m1; h >= 0; h--) {
uint32_t *s32 = (uint32_t *)src;
uint32_t *d32 = (uint32_t *)dst;
for (w = wh; w >= 0; w--) {
*d32++ = *s32++;
*d32++ = *s32++;
}
src = (uint8_t *)s32 + step8;
dst = (uint8_t *)d32 + step8;
}
#endif
if ((width & 0x3f) == 0) {
return;
}
src -= height * step;
dst -= height * step;
}
if ((width & 32) != 0) {
#if USE_M68K_ASM
h = height_m1;
asm volatile("\n"
"om_rascopy_single_L:\n"
" move.l (%[src]),(%[dst]) ;\n"
" adda.l %[step],%[src] ;\n"
" adda.l %[step],%[dst] ;\n"
" dbra %[h],om_rascopy_single_L ;\n"
:
[src] "+&a" (src),
[dst] "+&a" (dst),
[h] "+&d" (h)
:
[step] "r" (step)
:
"memory"
);
#else
for (h = height_m1; h >= 0; h--) {
*(uint32_t *)dst = *(uint32_t *)src;
dst += step;
src += step;
}
#endif
if ((width & 0x1f) == 0) {
return;
}
src += 4 - height * step;
dst += 4 - height * step;
}
wl = width & 0x1f;
mask = ALL1BITS << (32 - wl);
for (plane = 0; plane < planecount; plane++) {
om_set_rop(plane, rop[plane], mask);
}
#if USE_M68K_ASM
h = height_m1;
asm volatile("\n"
"om_rascopy_single_bit:\n"
" move.l (%[src]),(%[dst]) ;\n"
" adda.l %[step],%[src] ;\n"
" adda.l %[step],%[dst] ;\n"
" dbra %[h],om_rascopy_single_bit ;\n"
:
[src] "+&a" (src),
[dst] "+&a" (dst),
[h] "+&d" (h)
:
[step] "r" (step)
:
"memory"
);
#else
for (h = height_m1; h >= 0; h--) {
*(uint32_t *)dst = *(uint32_t *)src;
dst += step;
src += step;
}
#endif
for (plane = 0; plane < planecount; plane++) {
om_set_rop(plane, rop[plane], ALL1BITS);
}
}
static void
om4_rascopy_multi(uint8_t *dst0, uint8_t *src0, int16_t width, int16_t height)
{
uint8_t *dst1, *dst2, *dst3;
int wh;
int wl;
int rewind;
int step;
uint32_t mask;
int16_t height_m1;
int16_t w, h;
step = OMFB_STRIDE;
if (height < 0) {
step = -step;
height = -height;
}
height_m1 = height - 1;
dst1 = dst0 + OMFB_PLANEOFFS;
dst2 = dst1 + OMFB_PLANEOFFS;
dst3 = dst2 + OMFB_PLANEOFFS;
wh = width >> 6;
if (wh > 0) {
int step8 = step - wh * 8;
#if USE_M68K_ASM
wh--;
h = height_m1;
asm volatile("\n"
"om4_rascopy_multi_LL:\n"
" move.w %[wh],%[w] ;\n"
"1:\n"
" move.l (%[src0]),(%[dst0])+ ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst1])+ ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst2])+ ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst3])+ ;\n"
" addq.l #4,%[src0] ;\n"
" move.l (%[src0]),(%[dst3])+ ;\n"
" suba.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst2])+ ;\n"
" suba.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst1])+ ;\n"
" suba.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0])+,(%[dst0])+ ;\n"
" dbra %[w],1b ;\n"
" adda.l %[step8],%[src0] ;\n"
" adda.l %[step8],%[dst0] ;\n"
" adda.l %[step8],%[dst1] ;\n"
" adda.l %[step8],%[dst2] ;\n"
" adda.l %[step8],%[dst3] ;\n"
" dbra %[h],om4_rascopy_multi_LL ;\n"
:
[src0] "+&a" (src0),
[dst0] "+&a" (dst0),
[dst1] "+&a" (dst1),
[dst2] "+&a" (dst2),
[dst3] "+&a" (dst3),
[h] "+&d" (h),
[w] "=&d" (w)
:
[wh] "r" (wh),
[PLANEOFFS] "r" (OMFB_PLANEOFFS),
[step8] "r" (step8)
:
"memory"
);
#else
wh--;
for (h = height_m1; h >= 0; h--) {
for (w = wh; w >= 0; w--) {
*(uint32_t *)dst0 = *(uint32_t *)src0;
dst0 += 4;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst1 = *(uint32_t *)src0;
dst1 += 4;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst2 = *(uint32_t *)src0;
dst2 += 4;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst3 = *(uint32_t *)src0;
dst3 += 4;
src0 += 4;
*(uint32_t *)dst3 = *(uint32_t *)src0;
dst3 += 4;
src0 -= OMFB_PLANEOFFS;
*(uint32_t *)dst2 = *(uint32_t *)src0;
dst2 += 4;
src0 -= OMFB_PLANEOFFS;
*(uint32_t *)dst1 = *(uint32_t *)src0;
dst1 += 4;
src0 -= OMFB_PLANEOFFS;
*(uint32_t *)dst0 = *(uint32_t *)src0;
dst0 += 4;
src0 += 4;
}
src0 += step8;
dst0 += step8;
dst1 += step8;
dst2 += step8;
dst3 += step8;
}
#endif
if ((width & 0x3f) == 0) {
return;
}
src0 -= height * step;
dst0 -= height * step;
dst1 -= height * step;
dst2 -= height * step;
dst3 -= height * step;
}
rewind = OMFB_STRIDE - OMFB_PLANEOFFS * 3;
if ((width & 32) != 0) {
#if USE_M68K_ASM
h = height_m1;
asm volatile("\n"
"om4_rascopy_multi_L:\n"
" move.l (%[src0]),(%[dst0]) ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst1]) ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst2]) ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst3]) ;\n"
" adda.l %[rewind],%[src0] ;\n"
" adda.l %[step],%[dst0] ;\n"
" adda.l %[step],%[dst1] ;\n"
" adda.l %[step],%[dst2] ;\n"
" adda.l %[step],%[dst3] ;\n"
" dbra %[h],om4_rascopy_multi_L ;\n"
:
[src0] "+&a" (src0),
[dst0] "+&a" (dst0),
[dst1] "+&a" (dst1),
[dst2] "+&a" (dst2),
[dst3] "+&a" (dst3),
[h] "+&d" (h)
:
[PLANEOFFS] "r" (OMFB_PLANEOFFS),
[rewind] "r" (rewind),
[step] "r" (step)
:
"memory"
);
#else
for (h = height_m1; h >= 0; h--) {
*(uint32_t *)dst0 = *(uint32_t *)src0;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst1 = *(uint32_t *)src0;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst2 = *(uint32_t *)src0;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst3 = *(uint32_t *)src0;
src0 += rewind;
dst0 += step;
dst1 += step;
dst2 += step;
dst3 += step;
}
#endif
if ((width & 0x1f) == 0) {
return;
}
src0 += 4 - height * step;
dst0 += 4 - height * step;
dst1 += 4 - height * step;
dst2 += 4 - height * step;
dst3 += 4 - height * step;
}
wl = width & 0x1f;
mask = ALL1BITS << (32 - wl);
om_set_planemask(hwplanemask);
om_set_rop_curplane(ROP_THROUGH, mask);
#if USE_M68K_ASM
h = height_m1;
asm volatile("\n"
"om4_rascopy_multi_bit:\n"
" move.l (%[src0]),(%[dst0]) ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst1]) ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst2]) ;\n"
" adda.l %[PLANEOFFS],%[src0] ;\n"
" move.l (%[src0]),(%[dst3]) ;\n"
" adda.l %[rewind],%[src0] ;\n"
" adda.l %[step],%[dst0] ;\n"
" adda.l %[step],%[dst1] ;\n"
" adda.l %[step],%[dst2] ;\n"
" adda.l %[step],%[dst3] ;\n"
" dbra %[h],om4_rascopy_multi_bit ;\n"
:
[src0] "+&a" (src0),
[dst0] "+&a" (dst0),
[dst1] "+&a" (dst1),
[dst2] "+&a" (dst2),
[dst3] "+&a" (dst3),
[h] "+&d" (h)
:
[PLANEOFFS] "r" (OMFB_PLANEOFFS),
[rewind] "r" (rewind),
[step] "r" (step)
:
"memory"
);
#else
for (h = height_m1; h >= 0; h--) {
*(uint32_t *)dst0 = *(uint32_t *)src0;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst1 = *(uint32_t *)src0;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst2 = *(uint32_t *)src0;
src0 += OMFB_PLANEOFFS;
*(uint32_t *)dst3 = *(uint32_t *)src0;
src0 += rewind;
dst0 += step;
dst1 += step;
dst2 += step;
dst3 += step;
}
#endif
om_reset_planemask_and_rop();
}
static void
om1_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
{
struct rasops_info *ri = cookie;
uint8_t *p, *q;
int scanspan, offset, srcy, height, width, w;
uint32_t rmask;
scanspan = ri->ri_stride;
height = ri->ri_font->fontheight * nrows;
offset = (dstrow - srcrow) * scanspan * ri->ri_font->fontheight;
srcy = ri->ri_font->fontheight * srcrow;
if (srcrow < dstrow && srcrow + nrows > dstrow) {
scanspan = -scanspan;
srcy = srcy + height - 1;
}
p = (uint8_t *)ri->ri_bits + srcy * ri->ri_stride;
w = ri->ri_emuwidth;
width = w;
rmask = ALL1BITS << (-width & ALIGNMASK);
q = p;
while (height > 0) {
*P0(p + offset) = *P0(p);
width -= 2 * BLITWIDTH;
while (width > 0) {
p += BYTESDONE;
*P0(p + offset) = *P0(p);
width -= BLITWIDTH;
}
p += BYTESDONE;
*P0(p + offset) = (*P0(p) & rmask) | (*P0(p + offset) & ~rmask);
p = (q += scanspan);
width = w;
height--;
}
}
static void
om4_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
{
struct rasops_info *ri = cookie;
uint8_t *src, *dst;
int width, rowheight;
int planecount;
int ptrstep, rowstep;
int srcplane;
int i;
int r;
uint8_t rop[OMFB_MAX_PLANECOUNT];
width = ri->ri_emuwidth;
rowheight = ri->ri_font->fontheight;
planecount = ri->ri_depth;
src = (uint8_t *)ri->ri_bits + srcrow * rowheight * ri->ri_stride;
dst = (uint8_t *)ri->ri_bits + dstrow * rowheight * ri->ri_stride;
if (nrows <= 0 || srcrow == dstrow) {
return;
} else if (srcrow < dstrow) {
srcrow += nrows - 1;
dstrow += nrows - 1;
src += nrows * rowheight * ri->ri_stride - ri->ri_stride;
dst += nrows * rowheight * ri->ri_stride - ri->ri_stride;
rowstep = -1;
rowheight = -rowheight;
} else {
rowstep = 1;
}
ptrstep = ri->ri_stride * rowheight;
om_set_planemask(hwplanemask);
srcplane = 0;
while (nrows > 0) {
r = 1;
if (rowattr[srcrow].ismulti == false &&
rowattr[srcrow].fg == rowattr[srcrow].bg &&
rowattr[srcrow].all == rowattr[dstrow].all) {
goto skip;
}
for (; r < nrows; r++) {
if (rowattr[srcrow + r * rowstep].all !=
rowattr[srcrow].all) {
break;
}
}
if (rowattr[srcrow].ismulti) {
uint8_t *src0 = src + OMFB_PLANEOFFS;
uint8_t *dst0 = dst + OMFB_PLANEOFFS;
om_set_rop_curplane(ROP_THROUGH, ALL1BITS);
om4_rascopy_multi(dst0, src0, width, rowheight * r);
} else {
uint8_t *srcp;
uint8_t fg;
uint8_t bg;
uint8_t set;
fg = rowattr[srcrow].fg;
bg = rowattr[srcrow].bg;
set = fg ^ bg;
if (set == 0) {
set = fg;
} else if ((set & fg) != 0) {
set &= fg;
} else {
uint8_t tmp;
set &= bg;
tmp = fg;
fg = bg;
bg = tmp;
}
for (i = 0; i < planecount; i++) {
int t = om_fgbg2rop(fg, bg);
rop[i] = t;
om_set_rop(i, rop[i], ALL1BITS);
fg >>= 1;
bg >>= 1;
}
srcplane = (set != 0) ? (31 - __builtin_clz(set)) : 0;
srcp = src + OMFB_PLANEOFFS + srcplane * OMFB_PLANEOFFS;
om_rascopy_single(planecount, dst, srcp,
width, rowheight * r, rop);
}
skip:
for (i = 0; i < r; i++) {
rowattr[dstrow] = rowattr[srcrow];
srcrow += rowstep;
dstrow += rowstep;
src += ptrstep;
dst += ptrstep;
nrows--;
}
}
}
static void
om1_copycols(void *cookie, int startrow, int srccol, int dstcol, int ncols)
{
struct rasops_info *ri = cookie;
uint8_t *sp, *dp, *sq, *dq, *basep;
int scanspan, height, w, y, srcx, dstx;
int sb, eb, db, sboff, full, cnt, lnum, rnum;
uint32_t lmask, rmask, tmp;
bool sbover;
scanspan = ri->ri_stride;
y = ri->ri_font->fontheight * startrow;
srcx = ri->ri_font->fontwidth * srccol;
dstx = ri->ri_font->fontwidth * dstcol;
height = ri->ri_font->fontheight;
w = ri->ri_font->fontwidth * ncols;
basep = (uint8_t *)ri->ri_bits + y * scanspan;
sb = srcx & ALIGNMASK;
db = dstx & ALIGNMASK;
om_reset_planemask_and_rop();
if (db + w <= BLITWIDTH) {
sp = basep + (srcx / 32) * 4;
dp = basep + (dstx / 32) * 4;
while (height > 0) {
GETBITS(P0(sp), sb, w, tmp);
PUTBITS(tmp, db, w, P0(dp));
dp += scanspan;
sp += scanspan;
height--;
}
return;
}
lmask = (db == 0) ? 0 : ALL1BITS >> db;
eb = (db + w) & ALIGNMASK;
rmask = (eb == 0) ? 0 : ALL1BITS << (32 - eb);
lnum = (32 - db) & ALIGNMASK;
rnum = (dstx + w) & ALIGNMASK;
if (lmask != 0)
full = (w - (32 - db)) / 32;
else
full = w / 32;
sbover = (sb + lnum) >= 32;
if (dstcol < srccol || srccol + ncols < dstcol) {
sp = basep + (srcx / 32) * 4;
dp = basep + (dstx / 32) * 4;
if (lmask != 0) {
sboff = sb + lnum;
if (sboff >= 32)
sboff -= 32;
} else {
sboff = sb;
}
sq = sp;
dq = dp;
while (height > 0) {
if (lmask != 0) {
GETBITS(P0(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P0(dp));
dp += BYTESDONE;
if (sbover)
sp += BYTESDONE;
}
for (cnt = full; cnt; cnt--) {
GETBITS(P0(sp), sboff, 32, tmp);
*P0(dp) = tmp;
sp += BYTESDONE;
dp += BYTESDONE;
}
if (rmask != 0) {
GETBITS(P0(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P0(dp));
}
sp = (sq += scanspan);
dp = (dq += scanspan);
height--;
}
} else {
sp = basep + ((srcx + w) / 32) * 4;
dp = basep + ((dstx + w) / 32) * 4;
sboff = (srcx + w) & ALIGNMASK;
sboff -= rnum;
if (sboff < 0) {
sp -= BYTESDONE;
sboff += 32;
}
sq = sp;
dq = dp;
while (height > 0) {
if (rnum != 0) {
GETBITS(P0(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P0(dp));
}
for (cnt = full; cnt; cnt--) {
sp -= BYTESDONE;
dp -= BYTESDONE;
GETBITS(P0(sp), sboff, 32, tmp);
*P0(dp) = tmp;
}
if (lmask != 0) {
if (sbover)
sp -= BYTESDONE;
dp -= BYTESDONE;
GETBITS(P0(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P0(dp));
}
sp = (sq += scanspan);
dp = (dq += scanspan);
height--;
}
}
}
static void
om4_copycols(void *cookie, int startrow, int srccol, int dstcol, int ncols)
{
struct rasops_info *ri = cookie;
uint8_t *sp, *dp, *sq, *dq, *basep;
int scanspan, height, w, y, srcx, dstx;
int sb, eb, db, sboff, full, cnt, lnum, rnum;
uint32_t lmask, rmask, tmp;
bool sbover;
scanspan = ri->ri_stride;
y = ri->ri_font->fontheight * startrow;
srcx = ri->ri_font->fontwidth * srccol;
dstx = ri->ri_font->fontwidth * dstcol;
height = ri->ri_font->fontheight;
w = ri->ri_font->fontwidth * ncols;
basep = (uint8_t *)ri->ri_bits + y * scanspan;
sb = srcx & ALIGNMASK;
db = dstx & ALIGNMASK;
om_reset_planemask_and_rop();
if (db + w <= BLITWIDTH) {
sp = basep + (srcx / 32) * 4;
dp = basep + (dstx / 32) * 4;
while (height > 0) {
GETBITS(P0(sp), sb, w, tmp);
PUTBITS(tmp, db, w, P0(dp));
GETBITS(P1(sp), sb, w, tmp);
PUTBITS(tmp, db, w, P1(dp));
GETBITS(P2(sp), sb, w, tmp);
PUTBITS(tmp, db, w, P2(dp));
GETBITS(P3(sp), sb, w, tmp);
PUTBITS(tmp, db, w, P3(dp));
dp += scanspan;
sp += scanspan;
height--;
}
return;
}
lmask = (db == 0) ? 0 : ALL1BITS >> db;
eb = (db + w) & ALIGNMASK;
rmask = (eb == 0) ? 0 : ALL1BITS << (32 - eb);
lnum = (32 - db) & ALIGNMASK;
rnum = (dstx + w) & ALIGNMASK;
if (lmask != 0)
full = (w - (32 - db)) / 32;
else
full = w / 32;
sbover = (sb + lnum) >= 32;
if (dstcol < srccol || srccol + ncols < dstcol) {
sp = basep + (srcx / 32) * 4;
dp = basep + (dstx / 32) * 4;
if (lmask != 0) {
sboff = sb + lnum;
if (sboff >= 32)
sboff -= 32;
} else {
sboff = sb;
}
sq = sp;
dq = dp;
while (height > 0) {
if (lmask != 0) {
GETBITS(P0(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P0(dp));
GETBITS(P1(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P1(dp));
GETBITS(P2(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P2(dp));
GETBITS(P3(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P3(dp));
dp += BYTESDONE;
if (sbover)
sp += BYTESDONE;
}
for (cnt = full; cnt; cnt--) {
GETBITS(P0(sp), sboff, 32, tmp);
*P0(dp) = tmp;
GETBITS(P1(sp), sboff, 32, tmp);
*P1(dp) = tmp;
GETBITS(P2(sp), sboff, 32, tmp);
*P2(dp) = tmp;
GETBITS(P3(sp), sboff, 32, tmp);
*P3(dp) = tmp;
sp += BYTESDONE;
dp += BYTESDONE;
}
if (rmask != 0) {
GETBITS(P0(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P0(dp));
GETBITS(P1(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P1(dp));
GETBITS(P2(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P2(dp));
GETBITS(P3(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P3(dp));
}
sp = (sq += scanspan);
dp = (dq += scanspan);
height--;
}
} else {
sp = basep + ((srcx + w) / 32) * 4;
dp = basep + ((dstx + w) / 32) * 4;
sboff = (srcx + w) & ALIGNMASK;
sboff -= rnum;
if (sboff < 0) {
sp -= BYTESDONE;
sboff += 32;
}
sq = sp;
dq = dp;
while (height > 0) {
if (rnum != 0) {
GETBITS(P0(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P0(dp));
GETBITS(P1(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P1(dp));
GETBITS(P2(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P2(dp));
GETBITS(P3(sp), sboff, rnum, tmp);
PUTBITS(tmp, 0, rnum, P3(dp));
}
for (cnt = full; cnt; cnt--) {
sp -= BYTESDONE;
dp -= BYTESDONE;
GETBITS(P0(sp), sboff, 32, tmp);
*P0(dp) = tmp;
GETBITS(P1(sp), sboff, 32, tmp);
*P1(dp) = tmp;
GETBITS(P2(sp), sboff, 32, tmp);
*P2(dp) = tmp;
GETBITS(P3(sp), sboff, 32, tmp);
*P3(dp) = tmp;
}
if (lmask != 0) {
if (sbover)
sp -= BYTESDONE;
dp -= BYTESDONE;
GETBITS(P0(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P0(dp));
GETBITS(P1(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P1(dp));
GETBITS(P2(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P2(dp));
GETBITS(P3(sp), sb, lnum, tmp);
PUTBITS(tmp, db, lnum, P3(dp));
}
sp = (sq += scanspan);
dp = (dq += scanspan);
height--;
}
}
}
static int
om_mapchar(void *cookie, int c, u_int *cp)
{
struct rasops_info *ri = cookie;
struct wsdisplay_font *wf = ri->ri_font;
if (wf->encoding != WSDISPLAY_FONTENC_ISO) {
c = wsfont_map_unichar(wf, c);
if (c < 0)
goto fail;
}
if (c < wf->firstchar || c >= (wf->firstchar + wf->numchars))
goto fail;
*cp = c;
return 5;
fail:
*cp = ' ';
return 0;
}
static void
om_cursor(void *cookie, int on, int row, int col)
{
struct rasops_info *ri = cookie;
int startx;
int width;
int height;
int sh, sl;
int y;
int scanspan;
uint8_t *p;
if (!on) {
if ((ri->ri_flg & RI_CURSOR) == 0)
return;
row = ri->ri_crow;
col = ri->ri_ccol;
} else {
ri->ri_crow = row;
ri->ri_ccol = col;
}
scanspan = ri->ri_stride;
y = ri->ri_font->fontheight * row;
startx = ri->ri_font->fontwidth * col;
width = ri->ri_font->fontwidth;
height = ri->ri_font->fontheight;
sh = startx >> 5;
sl = startx & 0x1f;
p = (uint8_t *)ri->ri_bits + y * scanspan + sh * 4;
om_fill(hwplanemask, ROP_INV2, p, sl, scanspan, 0, width, height);
ri->ri_flg ^= RI_CURSOR;
om_reset_planemask_and_rop();
}
#if 0
#endif
static int
om_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
{
struct rasops_info *ri = cookie;
int planecount = ri->ri_depth;
uint32_t a;
uint16_t c;
a = 0;
c = 0;
if ((flags & WSATTR_BLINK) != 0)
return EINVAL;
if ((flags & WSATTR_WSCOLORS) == 0) {
fg = WSCOL_WHITE;
bg = WSCOL_BLACK;
}
if ((flags & WSATTR_REVERSE) != 0) {
int tmp;
tmp = fg;
fg = bg;
bg = tmp;
}
if ((flags & WSATTR_HILIT) != 0) {
if (planecount == 1) {
#if 0
a |= OMFB_ATTR_BOLD;
#else
return EINVAL;
#endif
} else if (fg < 8) {
fg += 8;
}
}
if ((flags & WSATTR_UNDERLINE) != 0) {
#if 0
a |= OMFB_ATTR_UNDERLINE;
#else
return EINVAL;
#endif
}
fg &= hwplanemask;
bg &= hwplanemask;
#if 0
int i;
for (i = 0; i < planecount; i++) {
c += c;
c += ((fg & 1) << 1) | (bg & 1);
fg >>= 1;
bg >>= 1;
}
#else
c = (fg << 8) | bg;
#endif
a |= c;
*attrp = a;
return 0;
}
static void
om_unpack_attr(long attr, uint8_t *fg, uint8_t *bg, int *underline)
{
uint8_t f, b;
f = (attr >> 8) & hwplanemask;
b = attr & hwplanemask;
if (fg)
*fg = f;
if (bg)
*bg = b;
}
int
omrasops1_init(struct rasops_info *ri, int wantrows, int wantcols)
{
omrasops_init(ri, wantrows, wantcols);
ri->ri_ops.cursor = om_cursor;
ri->ri_ops.mapchar = om_mapchar;
ri->ri_ops.putchar = om_putchar;
ri->ri_ops.copycols = om1_copycols;
ri->ri_ops.erasecols = om_erasecols;
ri->ri_ops.copyrows = om1_copyrows;
ri->ri_ops.eraserows = om_eraserows;
ri->ri_ops.allocattr = om_allocattr;
ri->ri_caps = WSSCREEN_REVERSE;
ri->ri_flg |= RI_CFGDONE;
return 0;
}
int
omrasops4_init(struct rasops_info *ri, int wantrows, int wantcols)
{
omrasops_init(ri, wantrows, wantcols);
ri->ri_ops.cursor = om_cursor;
ri->ri_ops.mapchar = om_mapchar;
ri->ri_ops.putchar = om_putchar;
ri->ri_ops.copycols = om4_copycols;
ri->ri_ops.erasecols = om_erasecols;
ri->ri_ops.copyrows = om4_copyrows;
ri->ri_ops.eraserows = om_eraserows;
ri->ri_ops.allocattr = om_allocattr;
ri->ri_caps = WSSCREEN_HILIT | WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
ri->ri_flg |= RI_CFGDONE;
return 0;
}
static int
omrasops_init(struct rasops_info *ri, int wantrows, int wantcols)
{
int wsfcookie, bpp;
if (wantrows > OMRASOPS_MAX_ROWS)
wantrows = OMRASOPS_MAX_ROWS;
if (wantrows == 0)
wantrows = 34;
if (wantrows < 10)
wantrows = 10;
if (wantcols == 0)
wantcols = 80;
if (wantcols < 20)
wantcols = 20;
wsfont_init();
wsfcookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
if (wsfcookie < 0)
panic("%s: no font available", __func__);
if (wsfont_lock(wsfcookie, &ri->ri_font))
panic("%s: unable to lock font", __func__);
ri->ri_wsfcookie = wsfcookie;
KASSERT(ri->ri_font->fontwidth > 4 && ri->ri_font->fontwidth <= 32);
bpp = 1;
ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
if (ri->ri_emuwidth > ri->ri_width)
ri->ri_emuwidth = ri->ri_width;
if (ri->ri_emuheight > ri->ri_height)
ri->ri_emuheight = ri->ri_height;
while ((ri->ri_emuwidth * bpp & 31) != 0)
ri->ri_emuwidth--;
ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
ri->ri_ccol = 0;
ri->ri_crow = 0;
ri->ri_pelbytes = bpp >> 3;
ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
if ((ri->ri_flg & RI_CLEAR) != 0)
memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
ri->ri_origbits = ri->ri_bits;
if ((ri->ri_flg & RI_CENTER) != 0) {
ri->ri_bits += (((ri->ri_width * bpp >> 3) -
ri->ri_emustride) >> 1) & ~3;
ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
ri->ri_stride;
ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
/ ri->ri_stride;
ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
% ri->ri_stride) * 8 / bpp);
} else
ri->ri_xorigin = ri->ri_yorigin = 0;
return 0;
}