omrasops.c revision 1.23 1 1.23 isaki /* $NetBSD: omrasops.c,v 1.23 2022/09/25 11:28:40 isaki Exp $ */
2 1.1 nisimura
3 1.1 nisimura /*-
4 1.1 nisimura * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 1.1 nisimura * All rights reserved.
6 1.1 nisimura *
7 1.1 nisimura * This code is derived from software contributed to The NetBSD Foundation
8 1.1 nisimura * by Tohru Nishimura.
9 1.1 nisimura *
10 1.1 nisimura * Redistribution and use in source and binary forms, with or without
11 1.1 nisimura * modification, are permitted provided that the following conditions
12 1.1 nisimura * are met:
13 1.1 nisimura * 1. Redistributions of source code must retain the above copyright
14 1.1 nisimura * notice, this list of conditions and the following disclaimer.
15 1.1 nisimura * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 nisimura * notice, this list of conditions and the following disclaimer in the
17 1.1 nisimura * documentation and/or other materials provided with the distribution.
18 1.1 nisimura *
19 1.1 nisimura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 nisimura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 nisimura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 nisimura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 nisimura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 nisimura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 nisimura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 nisimura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 nisimura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 nisimura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 nisimura * POSSIBILITY OF SUCH DAMAGE.
30 1.1 nisimura */
31 1.1 nisimura
32 1.1 nisimura #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
33 1.1 nisimura
34 1.23 isaki __KERNEL_RCSID(0, "$NetBSD: omrasops.c,v 1.23 2022/09/25 11:28:40 isaki Exp $");
35 1.1 nisimura
36 1.1 nisimura /*
37 1.1 nisimura * Designed speficically for 'm68k bitorder';
38 1.1 nisimura * - most significant byte is stored at lower address,
39 1.1 nisimura * - most significant bit is displayed at left most on screen.
40 1.12 tsutsui * Implementation relies on;
41 1.15 tsutsui * - first column is at 32bit aligned address,
42 1.1 nisimura * - font glyphs are stored in 32bit padded.
43 1.1 nisimura */
44 1.23 isaki /*
45 1.23 isaki * BMSEL affects both of
46 1.23 isaki * 1) which plane a write to the common bitmap plane is reflected on and
47 1.23 isaki * 2) which plane's ROP a write to the common ROP is reflected on.
48 1.23 isaki *
49 1.23 isaki * The common ROP is not a ROP applied to write to the common bitmap plane.
50 1.23 isaki * It's equivalent to set ROPs of the plane selected in the plane mask one
51 1.23 isaki * by one.
52 1.23 isaki */
53 1.1 nisimura
54 1.1 nisimura #include <sys/param.h>
55 1.1 nisimura #include <sys/systm.h>
56 1.1 nisimura #include <sys/device.h>
57 1.1 nisimura
58 1.13 tsutsui #include <dev/wscons/wsconsio.h>
59 1.1 nisimura #include <dev/wscons/wsdisplayvar.h>
60 1.13 tsutsui #include <dev/rasops/rasops.h>
61 1.1 nisimura
62 1.13 tsutsui #include <arch/luna68k/dev/omrasopsvar.h>
63 1.1 nisimura
64 1.23 isaki #ifdef luna68k
65 1.23 isaki #define USE_M68K_ASM 1
66 1.23 isaki #endif
67 1.23 isaki
68 1.23 isaki /* To provide optimization conditions to compilers */
69 1.23 isaki #if defined(__GNUC__)
70 1.23 isaki #define ASSUME(cond) if (!(cond)) __unreachable()
71 1.23 isaki #elif defined(__clang__) && __has_builtin(__builtin_assume)
72 1.23 isaki #define ASSUME(cond) __builtin_assume(cond)
73 1.23 isaki #else
74 1.23 isaki #define ASSUME(cond) (void)(cond)
75 1.23 isaki #endif
76 1.23 isaki
77 1.23 isaki /* XXX it should be redesigned, including making the attributes support 8bpp */
78 1.23 isaki typedef struct {
79 1.23 isaki union {
80 1.23 isaki int32_t all;
81 1.23 isaki struct {
82 1.23 isaki int8_t ismulti; /* is multi color used */
83 1.23 isaki uint8_t fg;
84 1.23 isaki uint8_t bg;
85 1.23 isaki uint8_t reserved;
86 1.23 isaki };
87 1.23 isaki };
88 1.23 isaki } rowattr_t;
89 1.23 isaki
90 1.1 nisimura /* wscons emulator operations */
91 1.23 isaki static void om_cursor(void *, int, int, int);
92 1.23 isaki static int om_mapchar(void *, int, u_int *);
93 1.23 isaki static void om_putchar(void *, int, int, u_int, long);
94 1.16 tsutsui static void om1_copycols(void *, int, int, int, int);
95 1.16 tsutsui static void om4_copycols(void *, int, int, int, int);
96 1.16 tsutsui static void om1_copyrows(void *, int, int, int num);
97 1.16 tsutsui static void om4_copyrows(void *, int, int, int num);
98 1.23 isaki static void om_erasecols(void *, int, int, int, long);
99 1.23 isaki static void om_eraserows(void *, int, int, long);
100 1.23 isaki static int om_allocattr(void *, int, int, int, long *);
101 1.23 isaki
102 1.23 isaki static void om_fill(int, int, uint8_t *, int, int, uint32_t, int, int);
103 1.23 isaki static void om_fill_color(int, uint8_t *, int, int, int, int);
104 1.23 isaki static void om_rascopy_single(uint8_t *, uint8_t *, int16_t, int16_t,
105 1.23 isaki uint8_t[]);
106 1.23 isaki static void om4_rascopy_multi(uint8_t *, uint8_t *, int16_t, int16_t);
107 1.23 isaki static void om_unpack_attr(long, uint8_t *, uint8_t *, int *);
108 1.16 tsutsui
109 1.16 tsutsui static int omrasops_init(struct rasops_info *, int, int);
110 1.1 nisimura
111 1.23 isaki /*
112 1.23 isaki * XXX should be fixed...
113 1.23 isaki * This number of elements is derived from howmany(1024, fontheight = 24).
114 1.23 isaki * But it is currently initialized with row = 34, so it is used only up to 34.
115 1.23 isaki */
116 1.23 isaki static rowattr_t rowattr[43];
117 1.23 isaki
118 1.1 nisimura #define ALL1BITS (~0U)
119 1.1 nisimura #define ALL0BITS (0U)
120 1.1 nisimura #define BLITWIDTH (32)
121 1.1 nisimura #define ALIGNMASK (0x1f)
122 1.1 nisimura #define BYTESDONE (4)
123 1.1 nisimura
124 1.23 isaki #if 0 /* XXX not used yet */
125 1.23 isaki /*
126 1.23 isaki * internal attributes. see om_allocattr().
127 1.23 isaki */
128 1.23 isaki #define OMFB_ATTR_MULTICOLOR (1U << 31)
129 1.23 isaki #define OMFB_ATTR_UNDERLINE (1U << 17)
130 1.23 isaki #define OMFB_ATTR_BOLD (1U << 16)
131 1.23 isaki #endif
132 1.23 isaki
133 1.23 isaki /*
134 1.23 isaki * XXX deprecated.
135 1.23 isaki * This way cannot be extended to 8bpp, so don't use it in new code.
136 1.23 isaki */
137 1.23 isaki #define P0(addr) ((uint32_t *)((uint8_t *)(addr) + OMFB_PLANEOFFS * 1))
138 1.23 isaki #define P1(addr) ((uint32_t *)((uint8_t *)(addr) + OMFB_PLANEOFFS * 2))
139 1.23 isaki #define P2(addr) ((uint32_t *)((uint8_t *)(addr) + OMFB_PLANEOFFS * 3))
140 1.23 isaki #define P3(addr) ((uint32_t *)((uint8_t *)(addr) + OMFB_PLANEOFFS * 4))
141 1.23 isaki
142 1.1 nisimura /*
143 1.15 tsutsui * macros to handle unaligned bit copy ops.
144 1.22 isaki * See src/sys/dev/rasops/rasops_masks.h for MI version.
145 1.15 tsutsui * Also refer src/sys/arch/hp300/dev/maskbits.h.
146 1.15 tsutsui * (which was implemented for ancient src/sys/arch/hp300/dev/grf_hy.c)
147 1.15 tsutsui */
148 1.15 tsutsui
149 1.15 tsutsui /* luna68k version GETBITS() that gets w bits from bit x at psrc memory */
150 1.15 tsutsui #define FASTGETBITS(psrc, x, w, dst) \
151 1.15 tsutsui asm("bfextu %3{%1:%2},%0" \
152 1.15 tsutsui : "=d" (dst) \
153 1.19 tsutsui : "di" (x), "di" (w), "o" (*(uint32_t *)(psrc)))
154 1.15 tsutsui
155 1.15 tsutsui /* luna68k version PUTBITS() that puts w bits from bit x at pdst memory */
156 1.15 tsutsui /* XXX this macro assumes (x + w) <= 32 to handle unaligned residual bits */
157 1.15 tsutsui #define FASTPUTBITS(src, x, w, pdst) \
158 1.15 tsutsui asm("bfins %3,%0{%1:%2}" \
159 1.19 tsutsui : "+o" (*(uint32_t *)(pdst)) \
160 1.16 tsutsui : "di" (x), "di" (w), "d" (src) \
161 1.22 isaki : "memory" )
162 1.15 tsutsui
163 1.15 tsutsui #define GETBITS(psrc, x, w, dst) FASTGETBITS(psrc, x, w, dst)
164 1.15 tsutsui #define PUTBITS(src, x, w, pdst) FASTPUTBITS(src, x, w, pdst)
165 1.15 tsutsui
166 1.15 tsutsui /*
167 1.23 isaki * Clear lower w bits from x.
168 1.23 isaki * x must be filled with 1 at least lower w bits.
169 1.1 nisimura */
170 1.23 isaki #if USE_M68K_ASM
171 1.23 isaki #define CLEAR_LOWER_BITS(x, w) \
172 1.23 isaki asm volatile( \
173 1.23 isaki " bclr %[width],%[data] ;\n" \
174 1.23 isaki " addq.l #1,%[data] ;\n" \
175 1.23 isaki : [data] "+&d" (x) \
176 1.23 isaki : [width] "d" (w) \
177 1.23 isaki : \
178 1.23 isaki )
179 1.23 isaki #else
180 1.23 isaki #define CLEAR_LOWER_BITS(x, w) x = ((x) & ~(1U << (w))) + 1
181 1.23 isaki #endif
182 1.23 isaki
183 1.23 isaki /* Set planemask for the common plane and the common ROP */
184 1.23 isaki static inline void
185 1.23 isaki om_set_planemask(int planemask)
186 1.23 isaki {
187 1.23 isaki
188 1.23 isaki *(volatile uint32_t *)OMFB_PLANEMASK = planemask;
189 1.23 isaki }
190 1.23 isaki
191 1.23 isaki /* Get a ROP address */
192 1.23 isaki static inline volatile uint32_t *
193 1.23 isaki om_rop_addr(int plane, int rop)
194 1.1 nisimura {
195 1.1 nisimura
196 1.23 isaki return (volatile uint32_t *)
197 1.23 isaki (OMFB_ROP_P0 + OMFB_PLANEOFFS * plane + rop * 4);
198 1.23 isaki }
199 1.1 nisimura
200 1.23 isaki /* Set ROP and ROP's mask for individual plane */
201 1.23 isaki static inline void
202 1.23 isaki om_set_rop(int plane, int rop, uint32_t mask)
203 1.23 isaki {
204 1.19 tsutsui
205 1.23 isaki *om_rop_addr(plane, rop) = mask;
206 1.23 isaki }
207 1.19 tsutsui
208 1.23 isaki /* Set ROP and ROP's mask for current setplanemask-ed plane(s) */
209 1.23 isaki static inline void
210 1.23 isaki om_set_rop_curplane(int rop, uint32_t mask)
211 1.23 isaki {
212 1.19 tsutsui
213 1.23 isaki ((volatile uint32_t *)(OMFB_ROP_COMMON))[rop] = mask;
214 1.23 isaki }
215 1.1 nisimura
216 1.23 isaki /* Reset planemask and ROP */
217 1.23 isaki static inline void
218 1.23 isaki om_reset_planemask_and_rop(void)
219 1.23 isaki {
220 1.19 tsutsui
221 1.23 isaki om_set_planemask(hwplanemask);
222 1.23 isaki om_set_rop_curplane(ROP_THROUGH, ~0U);
223 1.23 isaki }
224 1.19 tsutsui
225 1.23 isaki static inline void
226 1.23 isaki om_set_rowattr(int row, uint8_t fg, uint8_t bg)
227 1.23 isaki {
228 1.19 tsutsui
229 1.23 isaki if (rowattr[row].fg == fg && rowattr[row].bg == bg)
230 1.23 isaki return;
231 1.23 isaki if (rowattr[row].ismulti)
232 1.23 isaki return;
233 1.16 tsutsui
234 1.23 isaki if (rowattr[row].fg == rowattr[row].bg) {
235 1.23 isaki /* From the initial (erased) state, */
236 1.23 isaki if (rowattr[row].fg != fg && rowattr[row].bg != bg) {
237 1.23 isaki /* if both are changed at once, it's multi color */
238 1.23 isaki rowattr[row].ismulti = true;
239 1.23 isaki } else {
240 1.23 isaki /* otherwise, it's single color */
241 1.23 isaki rowattr[row].fg = fg;
242 1.23 isaki rowattr[row].bg = bg;
243 1.16 tsutsui }
244 1.23 isaki } else {
245 1.23 isaki rowattr[row].ismulti = true;
246 1.16 tsutsui }
247 1.16 tsutsui }
248 1.16 tsutsui
249 1.23 isaki static inline void
250 1.23 isaki om_reset_rowattr(int row, uint8_t bg)
251 1.23 isaki {
252 1.23 isaki
253 1.23 isaki /* Setting fg equal to bg means 'reset' or 'erased'. */
254 1.23 isaki rowattr[row].ismulti = false;
255 1.23 isaki rowattr[row].bg = bg;
256 1.23 isaki rowattr[row].fg = bg;
257 1.23 isaki }
258 1.23 isaki
259 1.23 isaki /*
260 1.23 isaki * Fill rectangle.
261 1.23 isaki * val is assumed only ALL0BITS or ALL1BITS, because all bits are used as is
262 1.23 isaki * regardless of bit offset of the destination.
263 1.23 isaki */
264 1.16 tsutsui static void
265 1.23 isaki om_fill(int planemask, int rop, uint8_t *dstptr, int dstbitoffs, int dstspan,
266 1.23 isaki uint32_t val, int width, int height)
267 1.16 tsutsui {
268 1.23 isaki uint32_t mask;
269 1.23 isaki uint32_t prev_mask;
270 1.23 isaki int32_t height_m1;
271 1.23 isaki int dw; /* 1 pass width bits */
272 1.23 isaki
273 1.23 isaki ASSUME(width > 0);
274 1.23 isaki ASSUME(height > 0);
275 1.23 isaki ASSUME(0 <= dstbitoffs && dstbitoffs < 32);
276 1.23 isaki
277 1.23 isaki om_set_planemask(planemask);
278 1.23 isaki
279 1.23 isaki height_m1 = height - 1;
280 1.23 isaki mask = ALL1BITS >> dstbitoffs;
281 1.23 isaki prev_mask = ~mask;
282 1.23 isaki dw = 32 - dstbitoffs;
283 1.23 isaki
284 1.23 isaki /* do-while loop seems slightly faster than a for loop */
285 1.23 isaki do {
286 1.23 isaki uint8_t *d;
287 1.23 isaki int32_t h;
288 1.23 isaki
289 1.23 isaki width -= dw;
290 1.23 isaki if (width < 0) {
291 1.23 isaki CLEAR_LOWER_BITS(mask, -width);
292 1.23 isaki /* To exit this loop. */
293 1.23 isaki width = 0;
294 1.23 isaki }
295 1.23 isaki
296 1.23 isaki if (prev_mask != mask) {
297 1.23 isaki om_set_rop_curplane(rop, mask);
298 1.23 isaki prev_mask = mask;
299 1.23 isaki }
300 1.23 isaki
301 1.23 isaki d = dstptr;
302 1.23 isaki dstptr += 4;
303 1.23 isaki h = height_m1;
304 1.23 isaki
305 1.23 isaki #if USE_M68K_ASM
306 1.23 isaki asm volatile("\n"
307 1.23 isaki "om_fill_loop_h:\n"
308 1.23 isaki " move.l %[val],(%[d]) ;\n"
309 1.23 isaki " add.l %[dstspan],%[d] ;\n"
310 1.23 isaki " dbra %[h],om_fill_loop_h ;\n"
311 1.23 isaki : /* output */
312 1.23 isaki [d] "+&a" (d),
313 1.23 isaki [h] "+&d" (h)
314 1.23 isaki : /* input */
315 1.23 isaki [val] "d" (val),
316 1.23 isaki [dstspan] "r" (dstspan)
317 1.23 isaki : /* clobbers */
318 1.23 isaki "memory"
319 1.23 isaki );
320 1.23 isaki #else
321 1.23 isaki do {
322 1.23 isaki *(uint32_t *)d = val;
323 1.23 isaki d += dstspan;
324 1.23 isaki } while (--h >= 0);
325 1.23 isaki #endif
326 1.23 isaki mask = ALL1BITS;
327 1.23 isaki dw = 32;
328 1.23 isaki } while (width > 0);
329 1.23 isaki }
330 1.23 isaki
331 1.23 isaki static void
332 1.23 isaki om_fill_color(int color, uint8_t *dstptr, int dstbitoffs, int dstspan,
333 1.23 isaki int width, int height)
334 1.23 isaki {
335 1.23 isaki uint32_t mask;
336 1.23 isaki uint32_t prev_mask;
337 1.23 isaki int32_t height_m1;
338 1.23 isaki int dw; /* 1 pass width bits */
339 1.23 isaki
340 1.23 isaki ASSUME(width > 0);
341 1.23 isaki ASSUME(height > 0);
342 1.23 isaki ASSUME(omfb_planecount > 0);
343 1.23 isaki
344 1.23 isaki /* select all planes */
345 1.23 isaki om_set_planemask(hwplanemask);
346 1.23 isaki
347 1.23 isaki mask = ALL1BITS >> dstbitoffs;
348 1.23 isaki prev_mask = ~mask;
349 1.23 isaki dw = 32 - dstbitoffs;
350 1.23 isaki height_m1 = height - 1;
351 1.23 isaki
352 1.23 isaki do {
353 1.23 isaki uint8_t *d;
354 1.23 isaki int32_t plane;
355 1.23 isaki int32_t h;
356 1.23 isaki int16_t rop;
357 1.23 isaki
358 1.23 isaki width -= dw;
359 1.23 isaki if (width < 0) {
360 1.23 isaki CLEAR_LOWER_BITS(mask, -width);
361 1.23 isaki /* To exit this loop. */
362 1.23 isaki width = 0;
363 1.23 isaki }
364 1.23 isaki
365 1.23 isaki if (prev_mask != mask) {
366 1.23 isaki for (plane = 0; plane < omfb_planecount; plane++) {
367 1.23 isaki if ((color & (1U << plane)) != 0)
368 1.23 isaki rop = ROP_ONE;
369 1.23 isaki else
370 1.23 isaki rop = ROP_ZERO;
371 1.23 isaki om_set_rop(plane, rop, mask);
372 1.23 isaki }
373 1.23 isaki prev_mask = mask;
374 1.23 isaki }
375 1.16 tsutsui
376 1.23 isaki d = dstptr;
377 1.23 isaki dstptr += 4;
378 1.23 isaki h = height_m1;
379 1.23 isaki
380 1.23 isaki #if USE_M68K_ASM
381 1.23 isaki asm volatile("\n"
382 1.23 isaki "om_fill_color_loop_h:\n"
383 1.23 isaki " clr.l (%[d]) ;\n"
384 1.23 isaki " add.l %[dstspan],%[d] ;\n"
385 1.23 isaki " dbra %[h],om_fill_color_loop_h ;\n"
386 1.23 isaki : /* output */
387 1.23 isaki [d] "+&a" (d),
388 1.23 isaki [h] "+&d" (h)
389 1.23 isaki : /* input */
390 1.23 isaki [dstspan] "r" (dstspan)
391 1.23 isaki : /* clobbers */
392 1.23 isaki "memory"
393 1.23 isaki );
394 1.23 isaki #else
395 1.23 isaki do {
396 1.23 isaki /*
397 1.23 isaki * ROP is either ONE or ZERO,
398 1.23 isaki * so don't care what you write to *d.
399 1.23 isaki */
400 1.23 isaki *(uint32_t *)d = 0;
401 1.23 isaki d += dstspan;
402 1.23 isaki } while (--h >= 0);
403 1.23 isaki #endif
404 1.23 isaki mask = ALL1BITS;
405 1.23 isaki dw = 32;
406 1.23 isaki } while (width > 0);
407 1.23 isaki }
408 1.19 tsutsui
409 1.23 isaki /*
410 1.23 isaki * Calculate ROP depending on fg/bg color combination as follows.
411 1.23 isaki * This is called per individual plane while shifting fg and bg.
412 1.23 isaki * So the LSB of fg and bg points to this plane.
413 1.23 isaki *
414 1.23 isaki * All ROP values we want to use here happens to be a multiple of 5.
415 1.23 isaki *
416 1.23 isaki * bg fg rop result
417 1.23 isaki * -- -- ---------------- ------
418 1.23 isaki * 0 0 ROP_ZERO = 0 0
419 1.23 isaki * 0 1 ROP_THROUGH = 5 D
420 1.23 isaki * 1 0 ROP_INV1 = 10 ~D
421 1.23 isaki * 1 1 ROP_ONE = 15 1
422 1.23 isaki *
423 1.23 isaki * This allows characters to be drawn in the specified fg/bg colors with
424 1.23 isaki * a single write to the common plane.
425 1.23 isaki */
426 1.23 isaki static inline int
427 1.23 isaki om_fgbg2rop(uint8_t fg, uint8_t bg)
428 1.23 isaki {
429 1.23 isaki int t;
430 1.19 tsutsui
431 1.23 isaki t = (bg & 1) * 2 + (fg & 1);
432 1.23 isaki return t * 5;
433 1.23 isaki }
434 1.19 tsutsui
435 1.23 isaki /*
436 1.23 isaki * Blit a character at the specified co-ordinates.
437 1.23 isaki * This function modifies(breaks) the planemask and ROPs.
438 1.23 isaki */
439 1.23 isaki static void
440 1.23 isaki om_putchar(void *cookie, int row, int startcol, u_int uc, long attr)
441 1.23 isaki {
442 1.23 isaki struct rasops_info *ri = cookie;
443 1.23 isaki uint8_t *fontptr;
444 1.23 isaki uint8_t *dstcmn;
445 1.23 isaki uint32_t mask;
446 1.23 isaki int width;
447 1.23 isaki int height;
448 1.23 isaki int x, y;
449 1.23 isaki int fontstride;
450 1.23 isaki int fontx;
451 1.23 isaki int plane;
452 1.23 isaki int dw; /* 1 pass width bits */
453 1.23 isaki int xh, xl;
454 1.23 isaki uint8_t fg, bg;
455 1.23 isaki /* ROP address cache */
456 1.23 isaki static volatile uint32_t *ropaddr[OMFB_MAX_PLANECOUNT];
457 1.23 isaki static uint8_t last_fg, last_bg;
458 1.19 tsutsui
459 1.23 isaki if (uc >= 0x80)
460 1.23 isaki return;
461 1.16 tsutsui
462 1.23 isaki width = ri->ri_font->fontwidth;
463 1.23 isaki height = ri->ri_font->fontheight;
464 1.23 isaki fontstride = ri->ri_font->stride;
465 1.23 isaki y = height * row;
466 1.23 isaki x = width * startcol;
467 1.23 isaki fontptr = (uint8_t *)ri->ri_font->data +
468 1.23 isaki (uc - ri->ri_font->firstchar) * ri->ri_fontscale;
469 1.19 tsutsui
470 1.23 isaki om_unpack_attr(attr, &fg, &bg, NULL);
471 1.23 isaki om_set_rowattr(row, fg, bg);
472 1.19 tsutsui
473 1.23 isaki if (last_fg != fg || last_bg != bg) {
474 1.23 isaki last_fg = fg;
475 1.23 isaki last_bg = bg;
476 1.23 isaki /* calculate ROP */
477 1.23 isaki for (plane = 0; plane < omfb_planecount; plane++) {
478 1.23 isaki int t = om_fgbg2rop(fg, bg);
479 1.23 isaki ropaddr[plane] = om_rop_addr(plane, t);
480 1.23 isaki fg >>= 1;
481 1.23 isaki bg >>= 1;
482 1.23 isaki }
483 1.23 isaki }
484 1.23 isaki
485 1.23 isaki /* divide x into the lower 5 bits and the rest. */
486 1.23 isaki xh = x >> 5;
487 1.23 isaki xl = x & 0x1f;
488 1.23 isaki
489 1.23 isaki /* write to common plane */
490 1.23 isaki dstcmn = (uint8_t *)ri->ri_bits + xh * 4 + y * OMFB_STRIDE;
491 1.23 isaki
492 1.23 isaki /* select all plane */
493 1.23 isaki om_set_planemask(hwplanemask);
494 1.23 isaki
495 1.23 isaki fontx = 0;
496 1.23 isaki mask = ALL1BITS >> xl;
497 1.23 isaki dw = 32 - xl;
498 1.23 isaki
499 1.23 isaki ASSUME(omfb_planecount == 1 ||
500 1.23 isaki omfb_planecount == 4 ||
501 1.23 isaki omfb_planecount == 8);
502 1.23 isaki
503 1.23 isaki do {
504 1.23 isaki uint8_t *d;
505 1.23 isaki uint8_t *f;
506 1.23 isaki int32_t h;
507 1.23 isaki
508 1.23 isaki width -= dw;
509 1.23 isaki if (width < 0) {
510 1.23 isaki CLEAR_LOWER_BITS(mask, -width);
511 1.23 isaki /* To exit this loop. */
512 1.23 isaki width = 0;
513 1.23 isaki }
514 1.23 isaki
515 1.23 isaki switch (omfb_planecount) {
516 1.23 isaki case 8:
517 1.23 isaki *(ropaddr[7]) = mask;
518 1.23 isaki *(ropaddr[6]) = mask;
519 1.23 isaki *(ropaddr[5]) = mask;
520 1.23 isaki *(ropaddr[4]) = mask;
521 1.23 isaki /* FALLTHROUGH */
522 1.23 isaki case 4:
523 1.23 isaki *(ropaddr[3]) = mask;
524 1.23 isaki *(ropaddr[2]) = mask;
525 1.23 isaki *(ropaddr[1]) = mask;
526 1.23 isaki /* FALLTHROUGH */
527 1.23 isaki case 1:
528 1.23 isaki *(ropaddr[0]) = mask;
529 1.23 isaki break;
530 1.23 isaki }
531 1.23 isaki
532 1.23 isaki d = dstcmn;
533 1.23 isaki f = fontptr;
534 1.23 isaki h = height - 1;
535 1.23 isaki do {
536 1.23 isaki uint32_t v;
537 1.23 isaki GETBITS(f, fontx, dw, v);
538 1.23 isaki /* no need to shift v because it's masked by ROP */
539 1.23 isaki *(uint32_t *)d = v;
540 1.23 isaki d += OMFB_STRIDE;
541 1.23 isaki f += fontstride;
542 1.23 isaki } while (--h >= 0);
543 1.23 isaki
544 1.23 isaki dstcmn += 4;
545 1.23 isaki fontx += dw;
546 1.23 isaki mask = ALL1BITS;
547 1.23 isaki dw = 32;
548 1.23 isaki } while (width > 0);
549 1.1 nisimura
550 1.23 isaki om_reset_planemask_and_rop();
551 1.1 nisimura }
552 1.1 nisimura
553 1.1 nisimura static void
554 1.23 isaki om_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
555 1.1 nisimura {
556 1.13 tsutsui struct rasops_info *ri = cookie;
557 1.23 isaki int startx;
558 1.23 isaki int width;
559 1.23 isaki int height;
560 1.23 isaki int sh, sl;
561 1.23 isaki int y;
562 1.23 isaki int scanspan;
563 1.13 tsutsui uint8_t *p;
564 1.23 isaki uint8_t fg, bg;
565 1.13 tsutsui
566 1.20 maya scanspan = ri->ri_stride;
567 1.13 tsutsui y = ri->ri_font->fontheight * row;
568 1.13 tsutsui startx = ri->ri_font->fontwidth * startcol;
569 1.23 isaki width = ri->ri_font->fontwidth * ncols;
570 1.13 tsutsui height = ri->ri_font->fontheight;
571 1.23 isaki om_unpack_attr(attr, &fg, &bg, NULL);
572 1.23 isaki sh = startx >> 5;
573 1.23 isaki sl = startx & 0x1f;
574 1.23 isaki p = (uint8_t *)ri->ri_bits + y * scanspan + sh * 4;
575 1.23 isaki
576 1.23 isaki /* I'm not sure */
577 1.23 isaki om_set_rowattr(row, fg, bg);
578 1.23 isaki
579 1.23 isaki if (bg == 0) {
580 1.23 isaki /* om_fill seems slightly efficient */
581 1.23 isaki om_fill(hwplanemask, ROP_ZERO,
582 1.23 isaki p, sl, scanspan, 0, width, height);
583 1.11 tsutsui } else {
584 1.23 isaki om_fill_color(bg, p, sl, scanspan, width, height);
585 1.23 isaki }
586 1.1 nisimura
587 1.23 isaki /* reset mask value */
588 1.23 isaki om_reset_planemask_and_rop();
589 1.1 nisimura }
590 1.1 nisimura
591 1.1 nisimura static void
592 1.23 isaki om_eraserows(void *cookie, int startrow, int nrows, long attr)
593 1.16 tsutsui {
594 1.16 tsutsui struct rasops_info *ri = cookie;
595 1.23 isaki int startx;
596 1.23 isaki int width;
597 1.23 isaki int height;
598 1.23 isaki int sh, sl;
599 1.23 isaki int y;
600 1.23 isaki int scanspan;
601 1.23 isaki int row;
602 1.16 tsutsui uint8_t *p;
603 1.23 isaki uint8_t fg, bg;
604 1.16 tsutsui
605 1.20 maya scanspan = ri->ri_stride;
606 1.23 isaki y = ri->ri_font->fontheight * startrow;
607 1.23 isaki startx = 0;
608 1.23 isaki width = ri->ri_emuwidth;
609 1.23 isaki height = ri->ri_font->fontheight * nrows;
610 1.23 isaki om_unpack_attr(attr, &fg, &bg, NULL);
611 1.23 isaki sh = startx >> 5;
612 1.23 isaki sl = startx & 0x1f;
613 1.23 isaki p = (uint8_t *)ri->ri_bits + y * scanspan + sh * 4;
614 1.23 isaki
615 1.23 isaki for (row = startrow; row < startrow + nrows; row++) {
616 1.23 isaki om_reset_rowattr(row, bg);
617 1.23 isaki }
618 1.23 isaki
619 1.23 isaki if (bg == 0) {
620 1.23 isaki /* om_fill seems slightly efficient */
621 1.23 isaki om_fill(hwplanemask, ROP_ZERO,
622 1.23 isaki p, sl, scanspan, 0, width, height);
623 1.16 tsutsui } else {
624 1.23 isaki om_fill_color(bg, p, sl, scanspan, width, height);
625 1.16 tsutsui }
626 1.23 isaki /* reset mask value */
627 1.23 isaki om_reset_planemask_and_rop();
628 1.16 tsutsui }
629 1.16 tsutsui
630 1.23 isaki /*
631 1.23 isaki * Single plane raster copy.
632 1.23 isaki * dst: destination plane pointer.
633 1.23 isaki * src: source plane pointer.
634 1.23 isaki * if y-forward, src > dst, point to left-top.
635 1.23 isaki * if y-backward, src < dst, point to left-bottom.
636 1.23 isaki * width: pixel width (must > 0)
637 1.23 isaki * height: pixel height (> 0 if forward, < 0 if backward)
638 1.23 isaki * rop: ROP array with omfb_planecount elements.
639 1.23 isaki *
640 1.23 isaki * This function modifies(breaks) the planemask and ROPs.
641 1.23 isaki */
642 1.16 tsutsui static void
643 1.23 isaki om_rascopy_single(uint8_t *dst, uint8_t *src, int16_t width, int16_t height,
644 1.23 isaki uint8_t rop[])
645 1.1 nisimura {
646 1.23 isaki uint32_t mask;
647 1.23 isaki int wh;
648 1.23 isaki int wl;
649 1.23 isaki int step;
650 1.23 isaki int plane;
651 1.23 isaki int16_t height_m1;
652 1.23 isaki int16_t w, h;
653 1.23 isaki
654 1.23 isaki step = OMFB_STRIDE;
655 1.23 isaki
656 1.23 isaki /*
657 1.23 isaki * X direction is always forward (or ascend order) to use (An)+
658 1.23 isaki * addressing mode in asm.
659 1.23 isaki */
660 1.23 isaki
661 1.23 isaki /* Reverse order Y if backward copy */
662 1.23 isaki if (height < 0) {
663 1.23 isaki /* The sign is managed by step, height is always positive */
664 1.23 isaki step = -step;
665 1.23 isaki height = -height;
666 1.23 isaki }
667 1.23 isaki height_m1 = height - 1;
668 1.23 isaki
669 1.23 isaki /*
670 1.23 isaki * On single, it's not necessary to process two longwords at a time,
671 1.23 isaki * but we do so for symmetry and speedup.
672 1.23 isaki */
673 1.23 isaki
674 1.23 isaki /* First, transfer a rectangle consist of two longwords */
675 1.23 isaki wh = (width >> 6);
676 1.23 isaki if (wh > 0) {
677 1.23 isaki int step8 = step - wh * 8;
678 1.23 isaki
679 1.23 isaki #if USE_M68K_ASM
680 1.23 isaki wh--; /* for dbra */
681 1.23 isaki h = height_m1;
682 1.23 isaki asm volatile("\n"
683 1.23 isaki "om_rascopy_single_LL:\n"
684 1.23 isaki " move.w %[wh],%[w] ;\n"
685 1.23 isaki "1:\n"
686 1.23 isaki " move.l (%[src])+,(%[dst])+ ;\n"
687 1.23 isaki " move.l (%[src])+,(%[dst])+ ;\n"
688 1.23 isaki " dbra %[w],1b ;\n"
689 1.23 isaki
690 1.23 isaki " adda.l %[step8],%[src] ;\n"
691 1.23 isaki " adda.l %[step8],%[dst] ;\n"
692 1.23 isaki " dbra %[h],om_rascopy_single_LL ;\n"
693 1.23 isaki : /* output */
694 1.23 isaki [src] "+&a" (src),
695 1.23 isaki [dst] "+&a" (dst),
696 1.23 isaki [h] "+&d" (h),
697 1.23 isaki [w] "=&d" (w)
698 1.23 isaki : /* input */
699 1.23 isaki [wh] "r" (wh),
700 1.23 isaki [step8] "r" (step8)
701 1.23 isaki : /* clobbers */
702 1.23 isaki "memory"
703 1.23 isaki );
704 1.23 isaki #else
705 1.23 isaki wh--; /* to match to asm side */
706 1.23 isaki for (h = height_m1; h >= 0; h--) {
707 1.23 isaki uint32_t *s32 = (uint32_t *)src;
708 1.23 isaki uint32_t *d32 = (uint32_t *)dst;
709 1.23 isaki for (w = wh; w >= 0; w--) {
710 1.23 isaki *d32++ = *s32++;
711 1.23 isaki *d32++ = *s32++;
712 1.23 isaki }
713 1.23 isaki src = (uint8_t *)s32 + step8;
714 1.23 isaki dst = (uint8_t *)d32 + step8;
715 1.23 isaki }
716 1.23 isaki #endif
717 1.23 isaki
718 1.23 isaki if ((width & 0x3f) == 0) {
719 1.23 isaki /* transfer completed */
720 1.23 isaki return;
721 1.23 isaki }
722 1.1 nisimura
723 1.23 isaki /* rewind y for the next transfer */
724 1.23 isaki src -= height * step;
725 1.23 isaki dst -= height * step;
726 1.23 isaki }
727 1.23 isaki
728 1.23 isaki if ((width & 32) != 0) {
729 1.23 isaki /* Transfer one longword since an odd longword */
730 1.23 isaki #if USE_M68K_ASM
731 1.23 isaki h = height_m1;
732 1.23 isaki asm volatile("\n"
733 1.23 isaki "om_rascopy_single_L:\n"
734 1.23 isaki " move.l (%[src]),(%[dst]) ;\n"
735 1.23 isaki " adda.l %[step],%[src] ;\n"
736 1.23 isaki " adda.l %[step],%[dst] ;\n"
737 1.23 isaki " dbra %[h],om_rascopy_single_L ;\n"
738 1.23 isaki : /* output */
739 1.23 isaki [src] "+&a" (src),
740 1.23 isaki [dst] "+&a" (dst),
741 1.23 isaki [h] "+&d" (h)
742 1.23 isaki : /* input */
743 1.23 isaki [step] "r" (step)
744 1.23 isaki : /* clobbers */
745 1.23 isaki "memory"
746 1.23 isaki );
747 1.23 isaki #else
748 1.23 isaki for (h = height_m1; h >= 0; h--) {
749 1.23 isaki *(uint32_t *)dst = *(uint32_t *)src;
750 1.23 isaki dst += step;
751 1.23 isaki src += step;
752 1.23 isaki }
753 1.23 isaki #endif
754 1.1 nisimura
755 1.23 isaki if ((width & 0x1f) == 0) {
756 1.23 isaki /* transfer completed */
757 1.23 isaki return;
758 1.1 nisimura }
759 1.23 isaki
760 1.23 isaki /* rewind y for the next transfer */
761 1.23 isaki src += 4 - height * step;
762 1.23 isaki dst += 4 - height * step;
763 1.23 isaki }
764 1.23 isaki
765 1.23 isaki wl = width & 0x1f;
766 1.23 isaki /* wl > 0 at this point */
767 1.23 isaki
768 1.23 isaki /* Then, transfer residual bits */
769 1.23 isaki
770 1.23 isaki mask = ALL1BITS << (32 - wl);
771 1.23 isaki /*
772 1.23 isaki * The common ROP cannot be used here. Because the hardware doesn't
773 1.23 isaki * allow you to set the mask while keeping the ROP states.
774 1.23 isaki */
775 1.23 isaki for (plane = 0; plane < omfb_planecount; plane++) {
776 1.23 isaki om_set_rop(plane, rop[plane], mask);
777 1.23 isaki }
778 1.23 isaki
779 1.23 isaki #if USE_M68K_ASM
780 1.23 isaki h = height_m1;
781 1.23 isaki asm volatile("\n"
782 1.23 isaki "om_rascopy_single_bit:\n"
783 1.23 isaki " move.l (%[src]),(%[dst]) ;\n"
784 1.23 isaki " adda.l %[step],%[src] ;\n"
785 1.23 isaki " adda.l %[step],%[dst] ;\n"
786 1.23 isaki " dbra %[h],om_rascopy_single_bit ;\n"
787 1.23 isaki : /* output */
788 1.23 isaki [src] "+&a" (src),
789 1.23 isaki [dst] "+&a" (dst),
790 1.23 isaki [h] "+&d" (h)
791 1.23 isaki : /* input */
792 1.23 isaki [step] "r" (step)
793 1.23 isaki : /* clobbers */
794 1.23 isaki "memory"
795 1.23 isaki );
796 1.23 isaki #else
797 1.23 isaki for (h = height_m1; h >= 0; h--) {
798 1.23 isaki *(uint32_t *)dst = *(uint32_t *)src;
799 1.23 isaki dst += step;
800 1.23 isaki src += step;
801 1.23 isaki }
802 1.23 isaki #endif
803 1.23 isaki
804 1.23 isaki for (plane = 0; plane < omfb_planecount; plane++) {
805 1.23 isaki om_set_rop(plane, rop[plane], ALL1BITS);
806 1.1 nisimura }
807 1.1 nisimura }
808 1.1 nisimura
809 1.23 isaki /*
810 1.23 isaki * Multiple plane raster copy.
811 1.23 isaki * dst0: destination pointer in Plane0.
812 1.23 isaki * src0: source pointer in Plane0.
813 1.23 isaki * if y-forward, src0 > dst0, point to left-top.
814 1.23 isaki * if y-backward, src0 < dst0, point to left-bottom.
815 1.23 isaki * width: pixel width (must > 0)
816 1.23 isaki * height: pixel height (> 0 if forward, < 0 if backward)
817 1.23 isaki *
818 1.23 isaki * This function modifies(breaks) the planemask and ROPs.
819 1.23 isaki */
820 1.1 nisimura static void
821 1.23 isaki om4_rascopy_multi(uint8_t *dst0, uint8_t *src0, int16_t width, int16_t height)
822 1.16 tsutsui {
823 1.23 isaki uint8_t *dst1, *dst2, *dst3;
824 1.23 isaki int wh;
825 1.23 isaki int wl;
826 1.23 isaki int rewind;
827 1.23 isaki int step;
828 1.23 isaki uint32_t mask;
829 1.23 isaki int16_t height_m1;
830 1.23 isaki int16_t w, h;
831 1.23 isaki
832 1.23 isaki step = OMFB_STRIDE;
833 1.23 isaki
834 1.23 isaki /*
835 1.23 isaki * X direction is always forward (or ascend order) to use (An)+
836 1.23 isaki * addressing mode in asm.
837 1.23 isaki */
838 1.23 isaki
839 1.23 isaki /* Reverse order Y if backward copy */
840 1.23 isaki if (height < 0) {
841 1.23 isaki /* The sign is managed by step, height is always positive */
842 1.23 isaki step = -step;
843 1.23 isaki height = -height;
844 1.23 isaki }
845 1.23 isaki height_m1 = height - 1;
846 1.23 isaki
847 1.23 isaki dst1 = dst0 + OMFB_PLANEOFFS;
848 1.23 isaki dst2 = dst1 + OMFB_PLANEOFFS;
849 1.23 isaki dst3 = dst2 + OMFB_PLANEOFFS;
850 1.23 isaki
851 1.23 isaki /* First, transfer a rectangle consist of two longwords */
852 1.23 isaki wh = width >> 6;
853 1.23 isaki if (wh > 0) {
854 1.23 isaki int step8 = step - wh * 8;
855 1.23 isaki
856 1.23 isaki #if USE_M68K_ASM
857 1.23 isaki wh--; /* for dbra */
858 1.23 isaki h = height_m1;
859 1.23 isaki asm volatile("\n"
860 1.23 isaki "om4_rascopy_multi_LL:\n"
861 1.23 isaki " move.w %[wh],%[w] ;\n"
862 1.23 isaki "1:\n"
863 1.23 isaki /*
864 1.23 isaki * Optimized for 68030.
865 1.23 isaki *
866 1.23 isaki * On LUNA, the following is faster than any of
867 1.23 isaki * "MOVE.L (An)+,(An)+", "MOVE.L (An,Dn),(An,Dn)", or
868 1.23 isaki * "MOVEM.L", due to the relationship of instruction
869 1.23 isaki * overlaps and access waits.
870 1.23 isaki *
871 1.23 isaki * The head time of (An)+ as source operand is 0 and
872 1.23 isaki * the head time of ADDA instruction is 2. If the
873 1.23 isaki * previous instruction has some write wait cycles,
874 1.23 isaki * i.e., tail cycles, (An)+ as source operand cannot
875 1.23 isaki * overlap it but ADDA instruction can.
876 1.23 isaki */
877 1.23 isaki " move.l (%[src0]),(%[dst0])+ ;\n" /* P0 */
878 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
879 1.23 isaki " move.l (%[src0]),(%[dst1])+ ;\n" /* P1 */
880 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
881 1.23 isaki " move.l (%[src0]),(%[dst2])+ ;\n" /* P2 */
882 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
883 1.23 isaki " move.l (%[src0]),(%[dst3])+ ;\n" /* P3 */
884 1.23 isaki /* Expect an overlap, so don't use (An)+ */
885 1.23 isaki " addq.l #4,%[src0] ;\n"
886 1.23 isaki
887 1.23 isaki " move.l (%[src0]),(%[dst3])+ ;\n" /* P3 */
888 1.23 isaki " suba.l %[PLANEOFFS],%[src0] ;\n"
889 1.23 isaki " move.l (%[src0]),(%[dst2])+ ;\n" /* P2 */
890 1.23 isaki " suba.l %[PLANEOFFS],%[src0] ;\n"
891 1.23 isaki " move.l (%[src0]),(%[dst1])+ ;\n" /* P1 */
892 1.23 isaki " suba.l %[PLANEOFFS],%[src0] ;\n"
893 1.23 isaki " move.l (%[src0])+,(%[dst0])+ ;\n" /* P0 */
894 1.23 isaki " dbra %[w],1b ;\n"
895 1.23 isaki
896 1.23 isaki " adda.l %[step8],%[src0] ;\n"
897 1.23 isaki " adda.l %[step8],%[dst0] ;\n"
898 1.23 isaki " adda.l %[step8],%[dst1] ;\n"
899 1.23 isaki " adda.l %[step8],%[dst2] ;\n"
900 1.23 isaki " adda.l %[step8],%[dst3] ;\n"
901 1.23 isaki " dbra %[h],om4_rascopy_multi_LL ;\n"
902 1.23 isaki : /* output */
903 1.23 isaki [src0] "+&a" (src0),
904 1.23 isaki [dst0] "+&a" (dst0),
905 1.23 isaki [dst1] "+&a" (dst1),
906 1.23 isaki [dst2] "+&a" (dst2),
907 1.23 isaki [dst3] "+&a" (dst3),
908 1.23 isaki [h] "+&d" (h),
909 1.23 isaki [w] "=&d" (w)
910 1.23 isaki : /* input */
911 1.23 isaki [wh] "r" (wh),
912 1.23 isaki [PLANEOFFS] "r" (OMFB_PLANEOFFS),
913 1.23 isaki [step8] "r" (step8)
914 1.23 isaki : /* clobbers */
915 1.23 isaki "memory"
916 1.23 isaki );
917 1.23 isaki #else
918 1.23 isaki wh--; /* to match to asm side */
919 1.23 isaki for (h = height_m1; h >= 0; h--) {
920 1.23 isaki for (w = wh; w >= 0; w--) {
921 1.23 isaki *(uint32_t *)dst0 = *(uint32_t *)src0;
922 1.23 isaki dst0 += 4;
923 1.23 isaki src0 += OMFB_PLANEOFFS;
924 1.23 isaki *(uint32_t *)dst1 = *(uint32_t *)src0;
925 1.23 isaki dst1 += 4;
926 1.23 isaki src0 += OMFB_PLANEOFFS;
927 1.23 isaki *(uint32_t *)dst2 = *(uint32_t *)src0;
928 1.23 isaki dst2 += 4;
929 1.23 isaki src0 += OMFB_PLANEOFFS;
930 1.23 isaki *(uint32_t *)dst3 = *(uint32_t *)src0;
931 1.23 isaki dst3 += 4;
932 1.23 isaki src0 += 4;
933 1.23 isaki
934 1.23 isaki *(uint32_t *)dst3 = *(uint32_t *)src0;
935 1.23 isaki dst3 += 4;
936 1.23 isaki src0 -= OMFB_PLANEOFFS;
937 1.23 isaki *(uint32_t *)dst2 = *(uint32_t *)src0;
938 1.23 isaki dst2 += 4;
939 1.23 isaki src0 -= OMFB_PLANEOFFS;
940 1.23 isaki *(uint32_t *)dst1 = *(uint32_t *)src0;
941 1.23 isaki dst1 += 4;
942 1.23 isaki src0 -= OMFB_PLANEOFFS;
943 1.23 isaki *(uint32_t *)dst0 = *(uint32_t *)src0;
944 1.23 isaki dst0 += 4;
945 1.23 isaki src0 += 4;
946 1.23 isaki }
947 1.23 isaki src0 += step8;
948 1.23 isaki dst0 += step8;
949 1.23 isaki dst1 += step8;
950 1.23 isaki dst2 += step8;
951 1.23 isaki dst3 += step8;
952 1.23 isaki }
953 1.23 isaki #endif
954 1.23 isaki
955 1.23 isaki if ((width & 0x3f) == 0) {
956 1.23 isaki /* transfer completed */
957 1.23 isaki return;
958 1.23 isaki }
959 1.16 tsutsui
960 1.23 isaki /* rewind y for the next transfer */
961 1.23 isaki src0 -= height * step;
962 1.23 isaki dst0 -= height * step;
963 1.23 isaki dst1 -= height * step;
964 1.23 isaki dst2 -= height * step;
965 1.23 isaki dst3 -= height * step;
966 1.23 isaki }
967 1.23 isaki
968 1.23 isaki /* This rewind rewinds the plane, so Y order is irrelevant */
969 1.23 isaki rewind = OMFB_STRIDE - OMFB_PLANEOFFS * 3;
970 1.23 isaki
971 1.23 isaki if ((width & 32) != 0) {
972 1.23 isaki /* Transfer one longword since an odd longword */
973 1.23 isaki #if USE_M68K_ASM
974 1.23 isaki h = height_m1;
975 1.23 isaki asm volatile("\n"
976 1.23 isaki "om4_rascopy_multi_L:\n"
977 1.23 isaki " move.l (%[src0]),(%[dst0]) ;\n"
978 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
979 1.23 isaki " move.l (%[src0]),(%[dst1]) ;\n"
980 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
981 1.23 isaki " move.l (%[src0]),(%[dst2]) ;\n"
982 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
983 1.23 isaki " move.l (%[src0]),(%[dst3]) ;\n"
984 1.23 isaki " adda.l %[rewind],%[src0] ;\n"
985 1.23 isaki
986 1.23 isaki " adda.l %[step],%[dst0] ;\n"
987 1.23 isaki " adda.l %[step],%[dst1] ;\n"
988 1.23 isaki " adda.l %[step],%[dst2] ;\n"
989 1.23 isaki " adda.l %[step],%[dst3] ;\n"
990 1.23 isaki " dbra %[h],om4_rascopy_multi_L ;\n"
991 1.23 isaki : /* output */
992 1.23 isaki [src0] "+&a" (src0),
993 1.23 isaki [dst0] "+&a" (dst0),
994 1.23 isaki [dst1] "+&a" (dst1),
995 1.23 isaki [dst2] "+&a" (dst2),
996 1.23 isaki [dst3] "+&a" (dst3),
997 1.23 isaki [h] "+&d" (h)
998 1.23 isaki : /* input */
999 1.23 isaki [PLANEOFFS] "r" (OMFB_PLANEOFFS),
1000 1.23 isaki [rewind] "r" (rewind),
1001 1.23 isaki [step] "r" (step)
1002 1.23 isaki : /* clobbers */
1003 1.23 isaki "memory"
1004 1.23 isaki );
1005 1.23 isaki #else
1006 1.23 isaki for (h = height_m1; h >= 0; h--) {
1007 1.23 isaki *(uint32_t *)dst0 = *(uint32_t *)src0;
1008 1.23 isaki src0 += OMFB_PLANEOFFS;
1009 1.23 isaki *(uint32_t *)dst1 = *(uint32_t *)src0;
1010 1.23 isaki src0 += OMFB_PLANEOFFS;
1011 1.23 isaki *(uint32_t *)dst2 = *(uint32_t *)src0;
1012 1.23 isaki src0 += OMFB_PLANEOFFS;
1013 1.23 isaki *(uint32_t *)dst3 = *(uint32_t *)src0;
1014 1.23 isaki src0 += rewind;
1015 1.23 isaki
1016 1.23 isaki dst0 += step;
1017 1.23 isaki dst1 += step;
1018 1.23 isaki dst2 += step;
1019 1.23 isaki dst3 += step;
1020 1.23 isaki }
1021 1.23 isaki #endif
1022 1.16 tsutsui
1023 1.23 isaki if ((width & 0x1f) == 0) {
1024 1.23 isaki /* transfer completed */
1025 1.23 isaki return;
1026 1.16 tsutsui }
1027 1.23 isaki
1028 1.23 isaki /* rewind y for the next transfer */
1029 1.23 isaki src0 += 4 - height * step;
1030 1.23 isaki dst0 += 4 - height * step;
1031 1.23 isaki dst1 += 4 - height * step;
1032 1.23 isaki dst2 += 4 - height * step;
1033 1.23 isaki dst3 += 4 - height * step;
1034 1.23 isaki }
1035 1.23 isaki
1036 1.23 isaki wl = width & 0x1f;
1037 1.23 isaki /* wl > 0 at this point */
1038 1.23 isaki
1039 1.23 isaki /* Then, transfer residual bits */
1040 1.23 isaki
1041 1.23 isaki mask = ALL1BITS << (32 - wl);
1042 1.23 isaki om_set_planemask(hwplanemask);
1043 1.23 isaki om_set_rop_curplane(ROP_THROUGH, mask);
1044 1.23 isaki
1045 1.23 isaki #if USE_M68K_ASM
1046 1.23 isaki h = height_m1;
1047 1.23 isaki asm volatile("\n"
1048 1.23 isaki "om4_rascopy_multi_bit:\n"
1049 1.23 isaki " move.l (%[src0]),(%[dst0]) ;\n"
1050 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
1051 1.23 isaki " move.l (%[src0]),(%[dst1]) ;\n"
1052 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
1053 1.23 isaki " move.l (%[src0]),(%[dst2]) ;\n"
1054 1.23 isaki " adda.l %[PLANEOFFS],%[src0] ;\n"
1055 1.23 isaki " move.l (%[src0]),(%[dst3]) ;\n"
1056 1.23 isaki " adda.l %[rewind],%[src0] ;\n"
1057 1.23 isaki
1058 1.23 isaki " adda.l %[step],%[dst0] ;\n"
1059 1.23 isaki " adda.l %[step],%[dst1] ;\n"
1060 1.23 isaki " adda.l %[step],%[dst2] ;\n"
1061 1.23 isaki " adda.l %[step],%[dst3] ;\n"
1062 1.23 isaki " dbra %[h],om4_rascopy_multi_bit ;\n"
1063 1.23 isaki : /* output */
1064 1.23 isaki [src0] "+&a" (src0),
1065 1.23 isaki [dst0] "+&a" (dst0),
1066 1.23 isaki [dst1] "+&a" (dst1),
1067 1.23 isaki [dst2] "+&a" (dst2),
1068 1.23 isaki [dst3] "+&a" (dst3),
1069 1.23 isaki [h] "+&d" (h)
1070 1.23 isaki : /* input */
1071 1.23 isaki [PLANEOFFS] "r" (OMFB_PLANEOFFS),
1072 1.23 isaki [rewind] "r" (rewind),
1073 1.23 isaki [step] "r" (step)
1074 1.23 isaki : /* clobbers */
1075 1.23 isaki "memory"
1076 1.23 isaki );
1077 1.23 isaki #else
1078 1.23 isaki for (h = height_m1; h >= 0; h--) {
1079 1.23 isaki *(uint32_t *)dst0 = *(uint32_t *)src0;
1080 1.23 isaki src0 += OMFB_PLANEOFFS;
1081 1.23 isaki *(uint32_t *)dst1 = *(uint32_t *)src0;
1082 1.23 isaki src0 += OMFB_PLANEOFFS;
1083 1.23 isaki *(uint32_t *)dst2 = *(uint32_t *)src0;
1084 1.23 isaki src0 += OMFB_PLANEOFFS;
1085 1.23 isaki *(uint32_t *)dst3 = *(uint32_t *)src0;
1086 1.23 isaki src0 += rewind;
1087 1.23 isaki
1088 1.23 isaki dst0 += step;
1089 1.23 isaki dst1 += step;
1090 1.23 isaki dst2 += step;
1091 1.23 isaki dst3 += step;
1092 1.16 tsutsui }
1093 1.23 isaki #endif
1094 1.23 isaki om_reset_planemask_and_rop();
1095 1.16 tsutsui }
1096 1.16 tsutsui
1097 1.16 tsutsui static void
1098 1.16 tsutsui om1_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1099 1.1 nisimura {
1100 1.13 tsutsui struct rasops_info *ri = cookie;
1101 1.13 tsutsui uint8_t *p, *q;
1102 1.1 nisimura int scanspan, offset, srcy, height, width, w;
1103 1.13 tsutsui uint32_t rmask;
1104 1.13 tsutsui
1105 1.13 tsutsui scanspan = ri->ri_stride;
1106 1.13 tsutsui height = ri->ri_font->fontheight * nrows;
1107 1.13 tsutsui offset = (dstrow - srcrow) * scanspan * ri->ri_font->fontheight;
1108 1.13 tsutsui srcy = ri->ri_font->fontheight * srcrow;
1109 1.1 nisimura if (srcrow < dstrow && srcrow + nrows > dstrow) {
1110 1.1 nisimura scanspan = -scanspan;
1111 1.14 tsutsui srcy = srcy + height - 1;
1112 1.1 nisimura }
1113 1.1 nisimura
1114 1.13 tsutsui p = (uint8_t *)ri->ri_bits + srcy * ri->ri_stride;
1115 1.13 tsutsui w = ri->ri_emuwidth;
1116 1.1 nisimura width = w;
1117 1.1 nisimura rmask = ALL1BITS << (-width & ALIGNMASK);
1118 1.1 nisimura q = p;
1119 1.1 nisimura while (height > 0) {
1120 1.19 tsutsui *P0(p + offset) = *P0(p); /* always aligned */
1121 1.1 nisimura width -= 2 * BLITWIDTH;
1122 1.1 nisimura while (width > 0) {
1123 1.1 nisimura p += BYTESDONE;
1124 1.19 tsutsui *P0(p + offset) = *P0(p);
1125 1.1 nisimura width -= BLITWIDTH;
1126 1.1 nisimura }
1127 1.1 nisimura p += BYTESDONE;
1128 1.19 tsutsui *P0(p + offset) = (*P0(p) & rmask) | (*P0(p + offset) & ~rmask);
1129 1.1 nisimura
1130 1.1 nisimura p = (q += scanspan);
1131 1.1 nisimura width = w;
1132 1.1 nisimura height--;
1133 1.1 nisimura }
1134 1.1 nisimura }
1135 1.1 nisimura
1136 1.1 nisimura static void
1137 1.16 tsutsui om4_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1138 1.16 tsutsui {
1139 1.16 tsutsui struct rasops_info *ri = cookie;
1140 1.23 isaki uint8_t *src, *dst;
1141 1.23 isaki int width, rowheight;
1142 1.23 isaki int ptrstep, rowstep;
1143 1.23 isaki int srcplane;
1144 1.23 isaki int i;
1145 1.23 isaki int r;
1146 1.23 isaki uint8_t rop[OMFB_MAX_PLANECOUNT];
1147 1.23 isaki
1148 1.23 isaki width = ri->ri_emuwidth;
1149 1.23 isaki rowheight = ri->ri_font->fontheight;
1150 1.23 isaki src = (uint8_t *)ri->ri_bits + srcrow * rowheight * ri->ri_stride;
1151 1.23 isaki dst = (uint8_t *)ri->ri_bits + dstrow * rowheight * ri->ri_stride;
1152 1.23 isaki
1153 1.23 isaki if (nrows <= 0 || srcrow == dstrow) {
1154 1.23 isaki return;
1155 1.23 isaki } else if (srcrow < dstrow) {
1156 1.23 isaki /* y-backward */
1157 1.16 tsutsui
1158 1.23 isaki /* select the bottom raster of the bottom row */
1159 1.23 isaki srcrow += nrows - 1;
1160 1.23 isaki dstrow += nrows - 1;
1161 1.23 isaki src += nrows * rowheight * ri->ri_stride - ri->ri_stride;
1162 1.23 isaki dst += nrows * rowheight * ri->ri_stride - ri->ri_stride;
1163 1.23 isaki rowstep = -1;
1164 1.23 isaki rowheight = -rowheight;
1165 1.23 isaki } else {
1166 1.23 isaki /* y-forward */
1167 1.23 isaki rowstep = 1;
1168 1.16 tsutsui }
1169 1.23 isaki ptrstep = ri->ri_stride * rowheight;
1170 1.23 isaki
1171 1.23 isaki om_set_planemask(hwplanemask);
1172 1.16 tsutsui
1173 1.23 isaki srcplane = 0;
1174 1.23 isaki while (nrows > 0) {
1175 1.23 isaki r = 1;
1176 1.23 isaki if (rowattr[srcrow].ismulti == false &&
1177 1.23 isaki rowattr[srcrow].fg == rowattr[srcrow].bg &&
1178 1.23 isaki rowattr[srcrow].all == rowattr[dstrow].all) {
1179 1.23 isaki goto skip;
1180 1.23 isaki }
1181 1.23 isaki
1182 1.23 isaki /* count the number of rows with the same attributes */
1183 1.23 isaki for (; r < nrows; r++) {
1184 1.23 isaki if (rowattr[srcrow + r * rowstep].all !=
1185 1.23 isaki rowattr[srcrow].all) {
1186 1.23 isaki break;
1187 1.23 isaki }
1188 1.16 tsutsui }
1189 1.23 isaki /* r is the number of rows including srcrow itself */
1190 1.23 isaki
1191 1.23 isaki if (rowattr[srcrow].ismulti) {
1192 1.23 isaki /*
1193 1.23 isaki * src,dst point to the common plane. src0,dst0 will
1194 1.23 isaki * point to the same offset in plane0 because plane0
1195 1.23 isaki * is placed just after the common plane.
1196 1.23 isaki */
1197 1.23 isaki uint8_t *src0 = src + OMFB_PLANEOFFS;
1198 1.23 isaki uint8_t *dst0 = dst + OMFB_PLANEOFFS;
1199 1.23 isaki om_set_rop_curplane(ROP_THROUGH, ALL1BITS);
1200 1.23 isaki om4_rascopy_multi(dst0, src0, width, rowheight * r);
1201 1.23 isaki } else {
1202 1.23 isaki uint8_t *srcp;
1203 1.23 isaki uint8_t fg;
1204 1.23 isaki uint8_t bg;
1205 1.23 isaki uint8_t set;
1206 1.23 isaki
1207 1.23 isaki fg = rowattr[srcrow].fg;
1208 1.23 isaki bg = rowattr[srcrow].bg;
1209 1.23 isaki set = fg ^ bg;
1210 1.23 isaki if (set == 0) {
1211 1.23 isaki /* use fg since both can be acceptable */
1212 1.23 isaki set = fg;
1213 1.23 isaki } else if ((set & fg) != 0) {
1214 1.23 isaki /*
1215 1.23 isaki * set is the set of bits that set in fg and
1216 1.23 isaki * cleared in bg.
1217 1.23 isaki */
1218 1.23 isaki set &= fg;
1219 1.23 isaki } else {
1220 1.23 isaki /*
1221 1.23 isaki * otherwise, set is the set of bits that
1222 1.23 isaki * (probably) set in bg and cleared in fg.
1223 1.23 isaki */
1224 1.23 isaki uint8_t tmp;
1225 1.23 isaki
1226 1.23 isaki set &= bg;
1227 1.23 isaki /* and swap fg and bg */
1228 1.23 isaki tmp = fg;
1229 1.23 isaki fg = bg;
1230 1.23 isaki bg = tmp;
1231 1.23 isaki }
1232 1.23 isaki
1233 1.23 isaki for (i = 0; i < omfb_planecount; i++) {
1234 1.23 isaki int t = om_fgbg2rop(fg, bg);
1235 1.23 isaki rop[i] = t;
1236 1.23 isaki om_set_rop(i, rop[i], ALL1BITS);
1237 1.23 isaki fg >>= 1;
1238 1.23 isaki bg >>= 1;
1239 1.23 isaki }
1240 1.16 tsutsui
1241 1.23 isaki /*
1242 1.23 isaki * If any bit in 'set' is set, any of them can be used.
1243 1.23 isaki * If all bits in 'set' are cleared, use plane 0.
1244 1.23 isaki * srcplane is the plane that fg is set and bg is
1245 1.23 isaki * cleared.
1246 1.23 isaki */
1247 1.23 isaki srcplane = (set != 0) ? (31 - __builtin_clz(set)) : 0;
1248 1.23 isaki
1249 1.23 isaki srcp = src + OMFB_PLANEOFFS + srcplane * OMFB_PLANEOFFS;
1250 1.23 isaki om_rascopy_single(dst, srcp, width, rowheight * r, rop);
1251 1.23 isaki }
1252 1.23 isaki
1253 1.23 isaki skip:
1254 1.23 isaki for (i = 0; i < r; i++) {
1255 1.23 isaki rowattr[dstrow] = rowattr[srcrow];
1256 1.23 isaki
1257 1.23 isaki srcrow += rowstep;
1258 1.23 isaki dstrow += rowstep;
1259 1.23 isaki src += ptrstep;
1260 1.23 isaki dst += ptrstep;
1261 1.23 isaki nrows--;
1262 1.23 isaki }
1263 1.16 tsutsui }
1264 1.16 tsutsui }
1265 1.16 tsutsui
1266 1.23 isaki /*
1267 1.23 isaki * XXX om{1,4}_copycols can be merged, but these are not frequently executed
1268 1.23 isaki * and have low execution costs. So I'm putting it off for now.
1269 1.23 isaki */
1270 1.23 isaki
1271 1.16 tsutsui static void
1272 1.16 tsutsui om1_copycols(void *cookie, int startrow, int srccol, int dstcol, int ncols)
1273 1.16 tsutsui {
1274 1.16 tsutsui struct rasops_info *ri = cookie;
1275 1.16 tsutsui uint8_t *sp, *dp, *sq, *dq, *basep;
1276 1.16 tsutsui int scanspan, height, w, y, srcx, dstx;
1277 1.16 tsutsui int sb, eb, db, sboff, full, cnt, lnum, rnum;
1278 1.16 tsutsui uint32_t lmask, rmask, tmp;
1279 1.16 tsutsui bool sbover;
1280 1.16 tsutsui
1281 1.16 tsutsui scanspan = ri->ri_stride;
1282 1.16 tsutsui y = ri->ri_font->fontheight * startrow;
1283 1.16 tsutsui srcx = ri->ri_font->fontwidth * srccol;
1284 1.16 tsutsui dstx = ri->ri_font->fontwidth * dstcol;
1285 1.16 tsutsui height = ri->ri_font->fontheight;
1286 1.16 tsutsui w = ri->ri_font->fontwidth * ncols;
1287 1.16 tsutsui basep = (uint8_t *)ri->ri_bits + y * scanspan;
1288 1.16 tsutsui
1289 1.16 tsutsui sb = srcx & ALIGNMASK;
1290 1.16 tsutsui db = dstx & ALIGNMASK;
1291 1.16 tsutsui
1292 1.23 isaki om_reset_planemask_and_rop();
1293 1.23 isaki
1294 1.16 tsutsui if (db + w <= BLITWIDTH) {
1295 1.16 tsutsui /* Destination is contained within a single word */
1296 1.16 tsutsui sp = basep + (srcx / 32) * 4;
1297 1.16 tsutsui dp = basep + (dstx / 32) * 4;
1298 1.16 tsutsui
1299 1.16 tsutsui while (height > 0) {
1300 1.16 tsutsui GETBITS(P0(sp), sb, w, tmp);
1301 1.16 tsutsui PUTBITS(tmp, db, w, P0(dp));
1302 1.16 tsutsui dp += scanspan;
1303 1.16 tsutsui sp += scanspan;
1304 1.16 tsutsui height--;
1305 1.16 tsutsui }
1306 1.16 tsutsui return;
1307 1.16 tsutsui }
1308 1.16 tsutsui
1309 1.16 tsutsui lmask = (db == 0) ? 0 : ALL1BITS >> db;
1310 1.16 tsutsui eb = (db + w) & ALIGNMASK;
1311 1.22 isaki rmask = (eb == 0) ? 0 : ALL1BITS << (32 - eb);
1312 1.16 tsutsui lnum = (32 - db) & ALIGNMASK;
1313 1.16 tsutsui rnum = (dstx + w) & ALIGNMASK;
1314 1.16 tsutsui
1315 1.16 tsutsui if (lmask != 0)
1316 1.16 tsutsui full = (w - (32 - db)) / 32;
1317 1.16 tsutsui else
1318 1.16 tsutsui full = w / 32;
1319 1.16 tsutsui
1320 1.16 tsutsui sbover = (sb + lnum) >= 32;
1321 1.16 tsutsui
1322 1.16 tsutsui if (dstcol < srccol || srccol + ncols < dstcol) {
1323 1.16 tsutsui /* copy forward (left-to-right) */
1324 1.16 tsutsui sp = basep + (srcx / 32) * 4;
1325 1.16 tsutsui dp = basep + (dstx / 32) * 4;
1326 1.16 tsutsui
1327 1.16 tsutsui if (lmask != 0) {
1328 1.16 tsutsui sboff = sb + lnum;
1329 1.16 tsutsui if (sboff >= 32)
1330 1.16 tsutsui sboff -= 32;
1331 1.23 isaki } else {
1332 1.16 tsutsui sboff = sb;
1333 1.23 isaki }
1334 1.16 tsutsui
1335 1.16 tsutsui sq = sp;
1336 1.16 tsutsui dq = dp;
1337 1.16 tsutsui while (height > 0) {
1338 1.16 tsutsui if (lmask != 0) {
1339 1.16 tsutsui GETBITS(P0(sp), sb, lnum, tmp);
1340 1.16 tsutsui PUTBITS(tmp, db, lnum, P0(dp));
1341 1.16 tsutsui dp += BYTESDONE;
1342 1.16 tsutsui if (sbover)
1343 1.16 tsutsui sp += BYTESDONE;
1344 1.16 tsutsui }
1345 1.16 tsutsui
1346 1.16 tsutsui for (cnt = full; cnt; cnt--) {
1347 1.16 tsutsui GETBITS(P0(sp), sboff, 32, tmp);
1348 1.19 tsutsui *P0(dp) = tmp;
1349 1.16 tsutsui sp += BYTESDONE;
1350 1.16 tsutsui dp += BYTESDONE;
1351 1.16 tsutsui }
1352 1.16 tsutsui
1353 1.16 tsutsui if (rmask != 0) {
1354 1.16 tsutsui GETBITS(P0(sp), sboff, rnum, tmp);
1355 1.16 tsutsui PUTBITS(tmp, 0, rnum, P0(dp));
1356 1.16 tsutsui }
1357 1.16 tsutsui
1358 1.16 tsutsui sp = (sq += scanspan);
1359 1.16 tsutsui dp = (dq += scanspan);
1360 1.16 tsutsui height--;
1361 1.16 tsutsui }
1362 1.16 tsutsui } else {
1363 1.16 tsutsui /* copy backward (right-to-left) */
1364 1.16 tsutsui sp = basep + ((srcx + w) / 32) * 4;
1365 1.16 tsutsui dp = basep + ((dstx + w) / 32) * 4;
1366 1.16 tsutsui
1367 1.16 tsutsui sboff = (srcx + w) & ALIGNMASK;
1368 1.16 tsutsui sboff -= rnum;
1369 1.16 tsutsui if (sboff < 0) {
1370 1.16 tsutsui sp -= BYTESDONE;
1371 1.16 tsutsui sboff += 32;
1372 1.16 tsutsui }
1373 1.16 tsutsui
1374 1.16 tsutsui sq = sp;
1375 1.16 tsutsui dq = dp;
1376 1.16 tsutsui while (height > 0) {
1377 1.16 tsutsui if (rnum != 0) {
1378 1.16 tsutsui GETBITS(P0(sp), sboff, rnum, tmp);
1379 1.16 tsutsui PUTBITS(tmp, 0, rnum, P0(dp));
1380 1.16 tsutsui }
1381 1.16 tsutsui
1382 1.16 tsutsui for (cnt = full; cnt; cnt--) {
1383 1.16 tsutsui sp -= BYTESDONE;
1384 1.16 tsutsui dp -= BYTESDONE;
1385 1.16 tsutsui GETBITS(P0(sp), sboff, 32, tmp);
1386 1.19 tsutsui *P0(dp) = tmp;
1387 1.16 tsutsui }
1388 1.16 tsutsui
1389 1.16 tsutsui if (lmask != 0) {
1390 1.16 tsutsui if (sbover)
1391 1.16 tsutsui sp -= BYTESDONE;
1392 1.16 tsutsui dp -= BYTESDONE;
1393 1.16 tsutsui GETBITS(P0(sp), sb, lnum, tmp);
1394 1.16 tsutsui PUTBITS(tmp, db, lnum, P0(dp));
1395 1.16 tsutsui }
1396 1.16 tsutsui
1397 1.16 tsutsui sp = (sq += scanspan);
1398 1.16 tsutsui dp = (dq += scanspan);
1399 1.16 tsutsui height--;
1400 1.16 tsutsui }
1401 1.16 tsutsui }
1402 1.16 tsutsui }
1403 1.16 tsutsui
1404 1.16 tsutsui static void
1405 1.16 tsutsui om4_copycols(void *cookie, int startrow, int srccol, int dstcol, int ncols)
1406 1.1 nisimura {
1407 1.13 tsutsui struct rasops_info *ri = cookie;
1408 1.15 tsutsui uint8_t *sp, *dp, *sq, *dq, *basep;
1409 1.15 tsutsui int scanspan, height, w, y, srcx, dstx;
1410 1.15 tsutsui int sb, eb, db, sboff, full, cnt, lnum, rnum;
1411 1.15 tsutsui uint32_t lmask, rmask, tmp;
1412 1.15 tsutsui bool sbover;
1413 1.1 nisimura
1414 1.13 tsutsui scanspan = ri->ri_stride;
1415 1.13 tsutsui y = ri->ri_font->fontheight * startrow;
1416 1.13 tsutsui srcx = ri->ri_font->fontwidth * srccol;
1417 1.13 tsutsui dstx = ri->ri_font->fontwidth * dstcol;
1418 1.13 tsutsui height = ri->ri_font->fontheight;
1419 1.13 tsutsui w = ri->ri_font->fontwidth * ncols;
1420 1.13 tsutsui basep = (uint8_t *)ri->ri_bits + y * scanspan;
1421 1.1 nisimura
1422 1.15 tsutsui sb = srcx & ALIGNMASK;
1423 1.15 tsutsui db = dstx & ALIGNMASK;
1424 1.1 nisimura
1425 1.23 isaki om_reset_planemask_and_rop();
1426 1.23 isaki
1427 1.15 tsutsui if (db + w <= BLITWIDTH) {
1428 1.15 tsutsui /* Destination is contained within a single word */
1429 1.15 tsutsui sp = basep + (srcx / 32) * 4;
1430 1.15 tsutsui dp = basep + (dstx / 32) * 4;
1431 1.1 nisimura
1432 1.1 nisimura while (height > 0) {
1433 1.16 tsutsui GETBITS(P0(sp), sb, w, tmp);
1434 1.16 tsutsui PUTBITS(tmp, db, w, P0(dp));
1435 1.16 tsutsui GETBITS(P1(sp), sb, w, tmp);
1436 1.16 tsutsui PUTBITS(tmp, db, w, P1(dp));
1437 1.16 tsutsui GETBITS(P2(sp), sb, w, tmp);
1438 1.16 tsutsui PUTBITS(tmp, db, w, P2(dp));
1439 1.16 tsutsui GETBITS(P3(sp), sb, w, tmp);
1440 1.16 tsutsui PUTBITS(tmp, db, w, P3(dp));
1441 1.1 nisimura dp += scanspan;
1442 1.1 nisimura sp += scanspan;
1443 1.1 nisimura height--;
1444 1.1 nisimura }
1445 1.15 tsutsui return;
1446 1.1 nisimura }
1447 1.1 nisimura
1448 1.15 tsutsui lmask = (db == 0) ? 0 : ALL1BITS >> db;
1449 1.15 tsutsui eb = (db + w) & ALIGNMASK;
1450 1.22 isaki rmask = (eb == 0) ? 0 : ALL1BITS << (32 - eb);
1451 1.15 tsutsui lnum = (32 - db) & ALIGNMASK;
1452 1.15 tsutsui rnum = (dstx + w) & ALIGNMASK;
1453 1.15 tsutsui
1454 1.15 tsutsui if (lmask != 0)
1455 1.15 tsutsui full = (w - (32 - db)) / 32;
1456 1.15 tsutsui else
1457 1.15 tsutsui full = w / 32;
1458 1.15 tsutsui
1459 1.15 tsutsui sbover = (sb + lnum) >= 32;
1460 1.15 tsutsui
1461 1.15 tsutsui if (dstcol < srccol || srccol + ncols < dstcol) {
1462 1.15 tsutsui /* copy forward (left-to-right) */
1463 1.15 tsutsui sp = basep + (srcx / 32) * 4;
1464 1.15 tsutsui dp = basep + (dstx / 32) * 4;
1465 1.15 tsutsui
1466 1.15 tsutsui if (lmask != 0) {
1467 1.15 tsutsui sboff = sb + lnum;
1468 1.15 tsutsui if (sboff >= 32)
1469 1.15 tsutsui sboff -= 32;
1470 1.23 isaki } else {
1471 1.15 tsutsui sboff = sb;
1472 1.23 isaki }
1473 1.15 tsutsui
1474 1.15 tsutsui sq = sp;
1475 1.15 tsutsui dq = dp;
1476 1.1 nisimura while (height > 0) {
1477 1.15 tsutsui if (lmask != 0) {
1478 1.16 tsutsui GETBITS(P0(sp), sb, lnum, tmp);
1479 1.16 tsutsui PUTBITS(tmp, db, lnum, P0(dp));
1480 1.16 tsutsui GETBITS(P1(sp), sb, lnum, tmp);
1481 1.16 tsutsui PUTBITS(tmp, db, lnum, P1(dp));
1482 1.16 tsutsui GETBITS(P2(sp), sb, lnum, tmp);
1483 1.16 tsutsui PUTBITS(tmp, db, lnum, P2(dp));
1484 1.16 tsutsui GETBITS(P3(sp), sb, lnum, tmp);
1485 1.16 tsutsui PUTBITS(tmp, db, lnum, P3(dp));
1486 1.15 tsutsui dp += BYTESDONE;
1487 1.15 tsutsui if (sbover)
1488 1.15 tsutsui sp += BYTESDONE;
1489 1.15 tsutsui }
1490 1.15 tsutsui
1491 1.15 tsutsui for (cnt = full; cnt; cnt--) {
1492 1.16 tsutsui GETBITS(P0(sp), sboff, 32, tmp);
1493 1.19 tsutsui *P0(dp) = tmp;
1494 1.16 tsutsui GETBITS(P1(sp), sboff, 32, tmp);
1495 1.19 tsutsui *P1(dp) = tmp;
1496 1.16 tsutsui GETBITS(P2(sp), sboff, 32, tmp);
1497 1.19 tsutsui *P2(dp) = tmp;
1498 1.16 tsutsui GETBITS(P3(sp), sboff, 32, tmp);
1499 1.19 tsutsui *P3(dp) = tmp;
1500 1.1 nisimura sp += BYTESDONE;
1501 1.1 nisimura dp += BYTESDONE;
1502 1.1 nisimura }
1503 1.15 tsutsui
1504 1.15 tsutsui if (rmask != 0) {
1505 1.16 tsutsui GETBITS(P0(sp), sboff, rnum, tmp);
1506 1.16 tsutsui PUTBITS(tmp, 0, rnum, P0(dp));
1507 1.16 tsutsui GETBITS(P1(sp), sboff, rnum, tmp);
1508 1.16 tsutsui PUTBITS(tmp, 0, rnum, P1(dp));
1509 1.16 tsutsui GETBITS(P2(sp), sboff, rnum, tmp);
1510 1.16 tsutsui PUTBITS(tmp, 0, rnum, P2(dp));
1511 1.16 tsutsui GETBITS(P3(sp), sboff, rnum, tmp);
1512 1.16 tsutsui PUTBITS(tmp, 0, rnum, P3(dp));
1513 1.15 tsutsui }
1514 1.15 tsutsui
1515 1.1 nisimura sp = (sq += scanspan);
1516 1.1 nisimura dp = (dq += scanspan);
1517 1.1 nisimura height--;
1518 1.1 nisimura }
1519 1.15 tsutsui } else {
1520 1.15 tsutsui /* copy backward (right-to-left) */
1521 1.15 tsutsui sp = basep + ((srcx + w) / 32) * 4;
1522 1.15 tsutsui dp = basep + ((dstx + w) / 32) * 4;
1523 1.15 tsutsui
1524 1.15 tsutsui sboff = (srcx + w) & ALIGNMASK;
1525 1.15 tsutsui sboff -= rnum;
1526 1.15 tsutsui if (sboff < 0) {
1527 1.15 tsutsui sp -= BYTESDONE;
1528 1.15 tsutsui sboff += 32;
1529 1.15 tsutsui }
1530 1.15 tsutsui
1531 1.15 tsutsui sq = sp;
1532 1.15 tsutsui dq = dp;
1533 1.1 nisimura while (height > 0) {
1534 1.15 tsutsui if (rnum != 0) {
1535 1.16 tsutsui GETBITS(P0(sp), sboff, rnum, tmp);
1536 1.16 tsutsui PUTBITS(tmp, 0, rnum, P0(dp));
1537 1.16 tsutsui GETBITS(P1(sp), sboff, rnum, tmp);
1538 1.16 tsutsui PUTBITS(tmp, 0, rnum, P1(dp));
1539 1.16 tsutsui GETBITS(P2(sp), sboff, rnum, tmp);
1540 1.16 tsutsui PUTBITS(tmp, 0, rnum, P2(dp));
1541 1.16 tsutsui GETBITS(P3(sp), sboff, rnum, tmp);
1542 1.16 tsutsui PUTBITS(tmp, 0, rnum, P3(dp));
1543 1.15 tsutsui }
1544 1.15 tsutsui
1545 1.15 tsutsui for (cnt = full; cnt; cnt--) {
1546 1.1 nisimura sp -= BYTESDONE;
1547 1.1 nisimura dp -= BYTESDONE;
1548 1.16 tsutsui GETBITS(P0(sp), sboff, 32, tmp);
1549 1.19 tsutsui *P0(dp) = tmp;
1550 1.16 tsutsui GETBITS(P1(sp), sboff, 32, tmp);
1551 1.19 tsutsui *P1(dp) = tmp;
1552 1.16 tsutsui GETBITS(P2(sp), sboff, 32, tmp);
1553 1.19 tsutsui *P2(dp) = tmp;
1554 1.16 tsutsui GETBITS(P3(sp), sboff, 32, tmp);
1555 1.19 tsutsui *P3(dp) = tmp;
1556 1.15 tsutsui }
1557 1.15 tsutsui
1558 1.15 tsutsui if (lmask != 0) {
1559 1.15 tsutsui if (sbover)
1560 1.15 tsutsui sp -= BYTESDONE;
1561 1.15 tsutsui dp -= BYTESDONE;
1562 1.16 tsutsui GETBITS(P0(sp), sb, lnum, tmp);
1563 1.16 tsutsui PUTBITS(tmp, db, lnum, P0(dp));
1564 1.16 tsutsui GETBITS(P1(sp), sb, lnum, tmp);
1565 1.16 tsutsui PUTBITS(tmp, db, lnum, P1(dp));
1566 1.16 tsutsui GETBITS(P2(sp), sb, lnum, tmp);
1567 1.16 tsutsui PUTBITS(tmp, db, lnum, P2(dp));
1568 1.16 tsutsui GETBITS(P3(sp), sb, lnum, tmp);
1569 1.16 tsutsui PUTBITS(tmp, db, lnum, P3(dp));
1570 1.1 nisimura }
1571 1.1 nisimura
1572 1.1 nisimura sp = (sq += scanspan);
1573 1.1 nisimura dp = (dq += scanspan);
1574 1.1 nisimura height--;
1575 1.1 nisimura }
1576 1.1 nisimura }
1577 1.1 nisimura }
1578 1.1 nisimura
1579 1.1 nisimura /*
1580 1.1 nisimura * Map a character.
1581 1.1 nisimura */
1582 1.1 nisimura static int
1583 1.8 dsl om_mapchar(void *cookie, int c, u_int *cp)
1584 1.1 nisimura {
1585 1.13 tsutsui struct rasops_info *ri = cookie;
1586 1.13 tsutsui struct wsdisplay_font *wf = ri->ri_font;
1587 1.11 tsutsui
1588 1.13 tsutsui if (wf->encoding != WSDISPLAY_FONTENC_ISO) {
1589 1.13 tsutsui c = wsfont_map_unichar(wf, c);
1590 1.13 tsutsui
1591 1.13 tsutsui if (c < 0)
1592 1.13 tsutsui goto fail;
1593 1.1 nisimura }
1594 1.13 tsutsui if (c < wf->firstchar || c >= (wf->firstchar + wf->numchars))
1595 1.13 tsutsui goto fail;
1596 1.13 tsutsui
1597 1.13 tsutsui *cp = c;
1598 1.13 tsutsui return 5;
1599 1.13 tsutsui
1600 1.13 tsutsui fail:
1601 1.1 nisimura *cp = ' ';
1602 1.11 tsutsui return 0;
1603 1.1 nisimura }
1604 1.1 nisimura
1605 1.1 nisimura /*
1606 1.1 nisimura * Position|{enable|disable} the cursor at the specified location.
1607 1.1 nisimura */
1608 1.1 nisimura static void
1609 1.23 isaki om_cursor(void *cookie, int on, int row, int col)
1610 1.1 nisimura {
1611 1.13 tsutsui struct rasops_info *ri = cookie;
1612 1.23 isaki int startx;
1613 1.23 isaki int width;
1614 1.23 isaki int height;
1615 1.23 isaki int sh, sl;
1616 1.23 isaki int y;
1617 1.23 isaki int scanspan;
1618 1.5 tsutsui uint8_t *p;
1619 1.1 nisimura
1620 1.1 nisimura if (!on) {
1621 1.1 nisimura /* make sure it's on */
1622 1.13 tsutsui if ((ri->ri_flg & RI_CURSOR) == 0)
1623 1.1 nisimura return;
1624 1.1 nisimura
1625 1.13 tsutsui row = ri->ri_crow;
1626 1.13 tsutsui col = ri->ri_ccol;
1627 1.1 nisimura } else {
1628 1.1 nisimura /* unpaint the old copy. */
1629 1.13 tsutsui ri->ri_crow = row;
1630 1.13 tsutsui ri->ri_ccol = col;
1631 1.1 nisimura }
1632 1.1 nisimura
1633 1.13 tsutsui scanspan = ri->ri_stride;
1634 1.13 tsutsui y = ri->ri_font->fontheight * row;
1635 1.13 tsutsui startx = ri->ri_font->fontwidth * col;
1636 1.23 isaki width = ri->ri_font->fontwidth;
1637 1.13 tsutsui height = ri->ri_font->fontheight;
1638 1.23 isaki sh = startx >> 5;
1639 1.23 isaki sl = startx & 0x1f;
1640 1.23 isaki p = (uint8_t *)ri->ri_bits + y * scanspan + sh * 4;
1641 1.1 nisimura
1642 1.23 isaki /* ROP_INV2 ignores data from MPU and inverts the current VRAM data */
1643 1.23 isaki om_fill(hwplanemask, ROP_INV2, p, sl, scanspan, 0, width, height);
1644 1.19 tsutsui
1645 1.16 tsutsui ri->ri_flg ^= RI_CURSOR;
1646 1.19 tsutsui
1647 1.23 isaki /* reset mask value */
1648 1.23 isaki om_reset_planemask_and_rop();
1649 1.1 nisimura }
1650 1.1 nisimura
1651 1.1 nisimura /*
1652 1.1 nisimura * Allocate attribute. We just pack these into an integer.
1653 1.23 isaki *
1654 1.23 isaki * Attribute bitmap:
1655 1.23 isaki * b31: Multi color (used by copyrows)
1656 1.23 isaki * b30-18: 0 (reserved)
1657 1.23 isaki * b17: Underline (not supported yet)
1658 1.23 isaki * b16: Bold (or HILIT if 1bpp; not supported yet)
1659 1.23 isaki * b15-8: fg color code
1660 1.23 isaki * b7-0: bg color code
1661 1.23 isaki */
1662 1.23 isaki #if 0
1663 1.23 isaki /*
1664 1.23 isaki * Future plan:
1665 1.23 isaki * Place fg and bg side by side in advance to reduce the computation cost
1666 1.23 isaki * at the time of ROP setting.
1667 1.23 isaki *
1668 1.23 isaki * bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1669 1.23 isaki * f7 b7 f6 b6 f5 b5 f4 b4 f3 b3 f2 b2 f1 b1 f0 b0
1670 1.23 isaki *
1671 1.23 isaki * In this form, use bit1..0 if 1bpp, use bit7..0 if 4bpp.
1672 1.1 nisimura */
1673 1.23 isaki #endif
1674 1.1 nisimura static int
1675 1.23 isaki om_allocattr(void *id, int fg, int bg, int flags, long *attrp)
1676 1.1 nisimura {
1677 1.23 isaki uint32_t a;
1678 1.23 isaki uint16_t c;
1679 1.23 isaki
1680 1.23 isaki a = 0;
1681 1.23 isaki c = 0;
1682 1.11 tsutsui
1683 1.23 isaki if ((flags & WSATTR_BLINK) != 0)
1684 1.11 tsutsui return EINVAL;
1685 1.1 nisimura
1686 1.16 tsutsui if ((flags & WSATTR_WSCOLORS) == 0) {
1687 1.23 isaki fg = WSCOL_WHITE; /* maybe 7 or 1 */
1688 1.23 isaki bg = WSCOL_BLACK; /* maybe 0 */
1689 1.16 tsutsui }
1690 1.16 tsutsui
1691 1.16 tsutsui if ((flags & WSATTR_REVERSE) != 0) {
1692 1.23 isaki int tmp;
1693 1.23 isaki tmp = fg;
1694 1.16 tsutsui fg = bg;
1695 1.23 isaki bg = tmp;
1696 1.16 tsutsui }
1697 1.16 tsutsui
1698 1.23 isaki if ((flags & WSATTR_HILIT) != 0) {
1699 1.23 isaki if (omfb_planecount == 1) {
1700 1.23 isaki #if 0
1701 1.23 isaki a |= OMFB_ATTR_BOLD;
1702 1.23 isaki #else
1703 1.23 isaki return EINVAL;
1704 1.23 isaki #endif
1705 1.23 isaki } else if (fg < 8) {
1706 1.23 isaki fg += 8;
1707 1.23 isaki }
1708 1.23 isaki }
1709 1.23 isaki
1710 1.23 isaki if ((flags & WSATTR_UNDERLINE) != 0) {
1711 1.23 isaki #if 0
1712 1.23 isaki a |= OMFB_ATTR_UNDERLINE;
1713 1.23 isaki #else
1714 1.23 isaki return EINVAL;
1715 1.23 isaki #endif
1716 1.23 isaki }
1717 1.16 tsutsui
1718 1.23 isaki fg &= hwplanemask;
1719 1.23 isaki bg &= hwplanemask;
1720 1.23 isaki
1721 1.23 isaki #if 0
1722 1.23 isaki int i;
1723 1.23 isaki for (i = 0; i < omfb_planecount; i++) {
1724 1.23 isaki c += c;
1725 1.23 isaki c += ((fg & 1) << 1) | (bg & 1);
1726 1.23 isaki fg >>= 1;
1727 1.23 isaki bg >>= 1;
1728 1.23 isaki }
1729 1.23 isaki #else
1730 1.23 isaki c = (fg << 8) | bg;
1731 1.23 isaki #endif
1732 1.23 isaki a |= c;
1733 1.23 isaki
1734 1.23 isaki *attrp = a;
1735 1.16 tsutsui return 0;
1736 1.16 tsutsui }
1737 1.16 tsutsui
1738 1.17 tsutsui static void
1739 1.23 isaki om_unpack_attr(long attr, uint8_t *fg, uint8_t *bg, int *underline)
1740 1.17 tsutsui {
1741 1.23 isaki uint8_t f, b;
1742 1.23 isaki
1743 1.23 isaki f = (attr >> 8) & hwplanemask;
1744 1.23 isaki b = attr & hwplanemask;
1745 1.17 tsutsui
1746 1.23 isaki if (fg)
1747 1.23 isaki *fg = f;
1748 1.23 isaki if (bg)
1749 1.23 isaki *bg = b;
1750 1.17 tsutsui }
1751 1.17 tsutsui
1752 1.13 tsutsui /*
1753 1.13 tsutsui * Init subset of rasops(9) for omrasops.
1754 1.13 tsutsui */
1755 1.13 tsutsui int
1756 1.16 tsutsui omrasops1_init(struct rasops_info *ri, int wantrows, int wantcols)
1757 1.16 tsutsui {
1758 1.16 tsutsui
1759 1.16 tsutsui omrasops_init(ri, wantrows, wantcols);
1760 1.16 tsutsui
1761 1.16 tsutsui /* fill our own emulops */
1762 1.23 isaki ri->ri_ops.cursor = om_cursor;
1763 1.16 tsutsui ri->ri_ops.mapchar = om_mapchar;
1764 1.23 isaki ri->ri_ops.putchar = om_putchar;
1765 1.16 tsutsui ri->ri_ops.copycols = om1_copycols;
1766 1.23 isaki ri->ri_ops.erasecols = om_erasecols;
1767 1.16 tsutsui ri->ri_ops.copyrows = om1_copyrows;
1768 1.23 isaki ri->ri_ops.eraserows = om_eraserows;
1769 1.23 isaki ri->ri_ops.allocattr = om_allocattr;
1770 1.16 tsutsui ri->ri_caps = WSSCREEN_REVERSE;
1771 1.16 tsutsui
1772 1.16 tsutsui ri->ri_flg |= RI_CFGDONE;
1773 1.16 tsutsui
1774 1.16 tsutsui return 0;
1775 1.16 tsutsui }
1776 1.16 tsutsui
1777 1.16 tsutsui int
1778 1.16 tsutsui omrasops4_init(struct rasops_info *ri, int wantrows, int wantcols)
1779 1.16 tsutsui {
1780 1.16 tsutsui
1781 1.16 tsutsui omrasops_init(ri, wantrows, wantcols);
1782 1.16 tsutsui
1783 1.16 tsutsui /* fill our own emulops */
1784 1.23 isaki ri->ri_ops.cursor = om_cursor;
1785 1.16 tsutsui ri->ri_ops.mapchar = om_mapchar;
1786 1.23 isaki ri->ri_ops.putchar = om_putchar;
1787 1.16 tsutsui ri->ri_ops.copycols = om4_copycols;
1788 1.23 isaki ri->ri_ops.erasecols = om_erasecols;
1789 1.16 tsutsui ri->ri_ops.copyrows = om4_copyrows;
1790 1.23 isaki ri->ri_ops.eraserows = om_eraserows;
1791 1.23 isaki ri->ri_ops.allocattr = om_allocattr;
1792 1.16 tsutsui ri->ri_caps = WSSCREEN_HILIT | WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
1793 1.16 tsutsui
1794 1.16 tsutsui ri->ri_flg |= RI_CFGDONE;
1795 1.16 tsutsui
1796 1.16 tsutsui return 0;
1797 1.16 tsutsui }
1798 1.16 tsutsui
1799 1.16 tsutsui static int
1800 1.13 tsutsui omrasops_init(struct rasops_info *ri, int wantrows, int wantcols)
1801 1.1 nisimura {
1802 1.13 tsutsui int wsfcookie, bpp;
1803 1.13 tsutsui
1804 1.13 tsutsui if (wantrows == 0)
1805 1.13 tsutsui wantrows = 34;
1806 1.13 tsutsui if (wantrows < 10)
1807 1.13 tsutsui wantrows = 10;
1808 1.13 tsutsui if (wantcols == 0)
1809 1.13 tsutsui wantcols = 80;
1810 1.13 tsutsui if (wantcols < 20)
1811 1.13 tsutsui wantcols = 20;
1812 1.13 tsutsui
1813 1.13 tsutsui /* Use default font */
1814 1.13 tsutsui wsfont_init();
1815 1.13 tsutsui wsfcookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
1816 1.13 tsutsui WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
1817 1.13 tsutsui if (wsfcookie < 0)
1818 1.13 tsutsui panic("%s: no font available", __func__);
1819 1.13 tsutsui if (wsfont_lock(wsfcookie, &ri->ri_font))
1820 1.13 tsutsui panic("%s: unable to lock font", __func__);
1821 1.13 tsutsui ri->ri_wsfcookie = wsfcookie;
1822 1.13 tsutsui
1823 1.13 tsutsui KASSERT(ri->ri_font->fontwidth > 4 && ri->ri_font->fontwidth <= 32);
1824 1.13 tsutsui
1825 1.16 tsutsui /* all planes are independently addressed */
1826 1.16 tsutsui bpp = 1;
1827 1.13 tsutsui
1828 1.13 tsutsui /* Now constrain what they get */
1829 1.13 tsutsui ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
1830 1.13 tsutsui ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
1831 1.13 tsutsui if (ri->ri_emuwidth > ri->ri_width)
1832 1.13 tsutsui ri->ri_emuwidth = ri->ri_width;
1833 1.13 tsutsui if (ri->ri_emuheight > ri->ri_height)
1834 1.13 tsutsui ri->ri_emuheight = ri->ri_height;
1835 1.13 tsutsui
1836 1.13 tsutsui /* Reduce width until aligned on a 32-bit boundary */
1837 1.13 tsutsui while ((ri->ri_emuwidth * bpp & 31) != 0)
1838 1.13 tsutsui ri->ri_emuwidth--;
1839 1.13 tsutsui
1840 1.13 tsutsui ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
1841 1.13 tsutsui ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
1842 1.13 tsutsui ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
1843 1.13 tsutsui ri->ri_ccol = 0;
1844 1.13 tsutsui ri->ri_crow = 0;
1845 1.13 tsutsui ri->ri_pelbytes = bpp >> 3;
1846 1.13 tsutsui
1847 1.13 tsutsui ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
1848 1.13 tsutsui ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
1849 1.13 tsutsui ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
1850 1.13 tsutsui
1851 1.13 tsutsui /* Clear the entire display */
1852 1.13 tsutsui if ((ri->ri_flg & RI_CLEAR) != 0)
1853 1.13 tsutsui memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
1854 1.13 tsutsui
1855 1.13 tsutsui /* Now centre our window if needs be */
1856 1.13 tsutsui ri->ri_origbits = ri->ri_bits;
1857 1.13 tsutsui
1858 1.13 tsutsui if ((ri->ri_flg & RI_CENTER) != 0) {
1859 1.13 tsutsui ri->ri_bits += (((ri->ri_width * bpp >> 3) -
1860 1.13 tsutsui ri->ri_emustride) >> 1) & ~3;
1861 1.13 tsutsui ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
1862 1.13 tsutsui ri->ri_stride;
1863 1.13 tsutsui ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
1864 1.13 tsutsui / ri->ri_stride;
1865 1.13 tsutsui ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
1866 1.13 tsutsui % ri->ri_stride) * 8 / bpp);
1867 1.13 tsutsui } else
1868 1.13 tsutsui ri->ri_xorigin = ri->ri_yorigin = 0;
1869 1.13 tsutsui
1870 1.13 tsutsui return 0;
1871 1.1 nisimura }
1872