ite_cc.c revision 1.1.1.2 1 #include "ite.h"
2 #if NITE > 0
3
4 #include "param.h"
5 #include "conf.h"
6 #include "proc.h"
7 #include "ioctl.h"
8 #include "tty.h"
9 #include "systm.h"
10
11 #include "ite.h"
12 #include "itevar.h"
13
14 #include "machine/cpu.h"
15
16 /* XXX */
17 #include "grfioctl.h"
18 #include "grfvar.h"
19 #include "grf_ccreg.h"
20
21 #include "../amiga/custom.h"
22
23 extern caddr_t CHIPMEMADDR;
24
25 extern unsigned char kernel_font_width, kernel_font_height;
26 extern unsigned char kernel_font_lo, kernel_font_hi;
27 extern unsigned char kernel_font[], kernel_cursor[];
28
29 /*
30 * This holds the instructions to retarget the plane 0 pointer
31 * at each split point.
32 */
33 typedef struct {
34 u_short wait[2]; /* wait instruction */
35 u_short plane[4]; /* move + hi word, move + lo word */
36 } COP_ROW;
37
38 typedef struct {
39 u_char *buf; /* pointer to row within frame buffer */
40 int polarity; /* polarity for loading planes in copper list */
41 } BUF_ROW;
42
43 /*
44 * This is what ip->priv points to;
45 * it contains local variables for custom-chip ites.
46 */
47 struct ccite {
48 struct ccfb *fb;
49 BUF_ROW *buf_rows; /* array of pointers into the frame buffer */
50 COP_ROW *cop_rows[2]; /* extension to grf_cc's copper lists */
51 };
52
53 static struct ccite ccite[NITE];
54
55 static BUF_ROW ccite_buf_rows[NITE][100]; /* XXX see below */
56
57 extern struct itesw itesw[];
58
59 /* 8-by-N routines */
60 static void cc_8n_cursor(struct ite_softc *ip, int flag);
61 static void cc_8n_putc(struct ite_softc *ip, int c, int dy, int dx, int mode);
62 static void cc_8n_clear(struct ite_softc *ip, int sy, int sx, int h, int w);
63 static void cc_8n_scroll(struct ite_softc *ip, int sy, int sx, int count, int dir);
64
65 /* (M<=8)-by-N routines */
66 static void cc_le32n_cursor(struct ite_softc *ip, int flag);
67 static void cc_le8n_putc(struct ite_softc *ip, int c, int dy, int dx, int mode);
68 static void cc_le8n_clear(struct ite_softc *ip, int sy, int sx, int h, int w);
69 static void cc_le8n_scroll(struct ite_softc *ip, int sy, int sx, int count, int dir);
70
71 /* Mykes: Insert your whiz-bang 8-by-8 routines here... ;-) */
72
73
74
75 customc_init(ip)
76 register struct ite_softc *ip;
77 {
78 struct ccite *cci;
79 struct ccfb *fb;
80 struct itesw *sp = &itesw[ip->type];
81
82 if (ip->grf == 0)
83 ip->grf = &grf_softc[ip - ite_softc];
84
85 cci = &ccite[ip - ite_softc];
86 ip->priv = cci;
87 fb = (struct ccfb *) ip->grf->g_display.gd_regaddr;
88 cci->fb = fb;
89
90 ip->font = kernel_font;
91 ip->font_lo = kernel_font_lo;
92 ip->font_hi = kernel_font_hi;
93 ip->ftwidth = kernel_font_width;
94 ip->ftheight = kernel_font_height;
95 #if 0
96 ip->cursor = kernel_cursor;
97 #endif
98
99 ip->rows = fb->disp_height / ip->ftheight;
100 ip->cols = fb->disp_width / ip->ftwidth;
101
102 /* Find the correct set of rendering routines for this font. */
103 #if 0
104 /* The new unspecialized routines are faster than the old specialized ones
105 for the same font!!! (and without even unrolling them...)
106 Therefore I'm leaving them out for now. */
107 if (ip->ftwidth == 8)
108 {
109 sp->ite_cursor = cc_8n_cursor;
110 sp->ite_putc = cc_8n_putc;
111 sp->ite_clear = cc_8n_clear;
112 sp->ite_scroll = cc_8n_scroll;
113 }
114 else
115 #endif
116 if (ip->ftwidth <= 8)
117 {
118 sp->ite_cursor = (void*)cc_le32n_cursor;
119 sp->ite_putc = (void*)cc_le8n_putc;
120 sp->ite_clear = (void*)cc_le8n_clear;
121 sp->ite_scroll = (void*)cc_le8n_scroll;
122 }
123 else
124 panic("kernel font size not supported");
125
126 /* XXX It may be better if this was dynamic based on ip->rows,
127 but is dynamic memory allocation available at this point? */
128 cci->buf_rows = ccite_buf_rows[ip - ite_softc];
129
130 /* Now allocate memory for the special screen-split copper lists.
131 We will need a COP_ROW structure for each text row,
132 plus an extra row to terminate the list. */
133 /* testing for the result is really redundant because chipmem_steal
134 panics if it runs out of memory.. */
135 if (! (cci->cop_rows[0] = (COP_ROW *)
136 chipmem_steal (sizeof(COP_ROW) * (ip->rows + 1)))
137 || !(cci->cop_rows[1] = (COP_ROW *)
138 chipmem_steal (sizeof(COP_ROW) * (ip->rows + 1))))
139 return 0;
140
141 /* Initialize the screen-split row arrays. */
142 {
143 int i, ypos = 0;
144 u_long rowbytes = fb->fb_width >> 3;
145 u_long fbp, fbp2;
146
147 fbp = ((u_long)fb->fb + (fb->fb_x >> 3) + fb->fb_y * rowbytes);
148 for (i = 0; i < ip->rows; i++)
149 {
150 cci->buf_rows[i].buf = (u_char*)fbp;
151 cci->buf_rows[i].polarity = (fb->disp_y + ypos) & 1;
152
153 COP_WAIT(cci->cop_rows[0][i].wait, (fb->disp_y + ypos + 1) >> 1);
154 fbp2 = (fbp - (u_long)CHIPMEMADDR
155 + (cci->buf_rows[i].polarity ? rowbytes : 0));
156 COP_MOVE(cci->cop_rows[0][i].plane, bplpth(0), HIADDR(fbp2));
157 COP_MOVE(cci->cop_rows[0][i].plane+2, bplptl(0), LOADDR(fbp2));
158
159 COP_WAIT(cci->cop_rows[1][i].wait, (fb->disp_y + ypos) >> 1);
160 fbp2 = (fbp - (u_long)CHIPMEMADDR +
161 (cci->buf_rows[i].polarity ? 0 : rowbytes));
162 COP_MOVE(cci->cop_rows[1][i].plane, bplpth(0), HIADDR(fbp2));
163 COP_MOVE(cci->cop_rows[1][i].plane+2, bplptl(0), LOADDR(fbp2));
164
165 ypos += ip->ftheight;
166 fbp += ip->ftheight * rowbytes;
167 }
168
169 /* Turn the display off after the last row;
170 otherwise we'll get funny text at the bottom of the screen
171 because of reordered rows. */
172 COP_WAIT(cci->cop_rows[0][i].wait+0, (fb->disp_y + ypos + 1) >> 1);
173 COP_MOVE(cci->cop_rows[0][i].wait+2, bplcon0, 0x8204);
174 COP_END (cci->cop_rows[0][i].wait+4);
175 COP_WAIT(cci->cop_rows[1][i].wait+0, (fb->disp_y + ypos) >> 1);
176 COP_MOVE(cci->cop_rows[1][i].wait+2, bplcon0, 0x8204);
177 COP_END (cci->cop_rows[1][i].wait+4);
178 }
179
180 /* Install the new copper list extensions. */
181 cc_install_cop_ext(ip->grf, cci->cop_rows[0], cci->cop_rows[1]);
182
183 #if 0
184 printf ("font@%x, cursor@%x\n", ip->font, ip->cursor);
185 dump_copperlist (fb->cop1);
186 dump_copperlist (fb->cop2);
187 #endif
188 }
189
190 customc_deinit(ip)
191 struct ite_softc *ip;
192 {
193 ip->flags &= ~ITE_INITED;
194
195 /* Take our grubby little fingers out of the grf's copper list. */
196 cc_uninstall_cop_ext(ip->grf);
197 }
198
199 /*
200 * Swap two text rows in the display by modifying the copper list.
201 */
202 static __inline int
203 swap_rows(struct ite_softc *ip, int row1, int row2)
204 {
205 struct ccite *cci = (struct ccite *) ip->priv;
206 int rowbytes = cci->fb->fb_width >> 3;
207 u_char *tmp, *fbp2;
208
209 /* Swap the plane pointers */
210 tmp = cci->buf_rows[row1].buf;
211 cci->buf_rows[row1].buf = cci->buf_rows[row2].buf;
212 cci->buf_rows[row2].buf = tmp;
213
214 /* Update the copper lists */
215 fbp2 = (cci->buf_rows[row1].buf - (u_long)CHIPMEMADDR
216 + (cci->buf_rows[row1].polarity ? rowbytes : 0));
217 cci->cop_rows[0][row1].plane[1] = HIADDR(fbp2);
218 cci->cop_rows[0][row1].plane[3] = LOADDR(fbp2);
219
220 fbp2 = (cci->buf_rows[row1].buf - (u_long)CHIPMEMADDR
221 + (cci->buf_rows[row1].polarity ? 0 : rowbytes));
222 cci->cop_rows[1][row1].plane[1] = HIADDR(fbp2);
223 cci->cop_rows[1][row1].plane[3] = LOADDR(fbp2);
224
225 fbp2 = (cci->buf_rows[row2].buf - (u_long)CHIPMEMADDR
226 + (cci->buf_rows[row2].polarity ? rowbytes : 0));
227 cci->cop_rows[0][row2].plane[1] = HIADDR(fbp2);
228 cci->cop_rows[0][row2].plane[3] = LOADDR(fbp2);
229
230 fbp2 = (cci->buf_rows[row2].buf - (u_long)CHIPMEMADDR
231 + (cci->buf_rows[row2].polarity ? 0 : rowbytes));
232 cci->cop_rows[1][row2].plane[1] = HIADDR(fbp2);
233 cci->cop_rows[1][row2].plane[3] = LOADDR(fbp2);
234
235 /* If the drawn cursor was on either row, swap it too. */
236 if (ip->cursory == row1)
237 ip->cursory = row2;
238 else if (ip->cursory == row2)
239 ip->cursory = row1;
240 }
241
242
243
244 /*** 8-by-N routines ***/
245
246 static inline void
247 cc_8n_windowmove (src, srcx, srcy, srcmod,
248 dst, dstx, dsty, dstmod, h, w, op)
249 unsigned char *src, *dst;
250 unsigned short srcx, srcy, srcmod;
251 unsigned short dstx, dsty, dstmod;
252 unsigned short h, w;
253 unsigned char op;
254 {
255 short i; /* NOT unsigned! */
256 unsigned char h1;
257
258 src += srcmod * srcy + (srcx >> 3);
259 dst += dstmod * dsty + (dstx >> 3);
260
261 #if 0
262 printf("ccwm: %x-%x-%x-%x-%c\n", src, dst, h, w,
263 op == RR_XOR ? '^' : op == RR_COPY ? '|' : op == RR_CLEAR ? 'C' : 'I');
264 #endif
265
266 /* currently, only drawing to byte slots is supported... */
267 if ((srcx & 07) || (dstx & 07) || (w & 07))
268 panic ("customc_windowmove: odd offset");
269
270 w >>= 3;
271
272 /* Ok, this is nastier than it could be to help the optimizer unroll
273 loops for the most common case of 8x8 characters.
274
275 Note that bzero() does some clever optimizations for large range
276 clears, so it should pay the subroutine call. */
277
278 /* perform OP on one bit row of data. */
279 #define ONEOP(dst, src, op) \
280 do { if ((src) > (dst)) \
281 for (i = 0; i < w; i++) (dst)[i] op (src)[i]; \
282 else \
283 for (i = w - 1; i >= 0; i--) (dst)[i] op (src)[i]; } while (0)
284
285 /* perform a block of eight ONEOPs. This enables the optimizer to unroll
286 the for-statements, as they have a loop counter known at compiletime */
287 #define EIGHTOP(dst, src, op) \
288 for (h1 = 0; h1 < 8; h1++, src += srcmod, dst += dstmod) \
289 ONEOP (dst, src, op);
290
291 switch (op)
292 {
293 case RR_COPY:
294 for (; h >= 8; h -= 8)
295 EIGHTOP (dst, src, =);
296 for (; h > 0; h--, src += srcmod, dst += dstmod)
297 ONEOP (dst, src, =);
298 break;
299
300 case RR_CLEAR:
301 for (; h >= 8; h -= 8)
302 for (h1 = 0; h1 < 8; h1++, dst += dstmod)
303 bzero (dst, w);
304 for (; h > 0; h--, dst += dstmod)
305 bzero (dst, w);
306 break;
307
308 case RR_XOR:
309 for (; h >= 8; h -= 8)
310 EIGHTOP (dst, src, ^=);
311 for (; h > 0; h--, src += srcmod, dst += dstmod)
312 ONEOP (dst, src, ^=);
313 break;
314
315 case RR_COPYINVERTED:
316 for (; h >= 8; h -= 8)
317 EIGHTOP (dst, src, =~);
318 for (; h > 0; h--, src += srcmod, dst += dstmod)
319 ONEOP (dst, src, =~);
320 break;
321 }
322 }
323
324
325 static void
326 cc_8n_cursor(ip, flag)
327 register struct ite_softc *ip;
328 register int flag;
329 {
330 struct ccite *cci = (struct ccite *) ip->priv;
331 struct ccfb *fb = cci->fb;
332 /* the cursor is always drawn in the last plane */
333 unsigned char *ovplane, opclr, opset;
334
335 ovplane = fb->fb + (fb->fb_z - 1) * (fb->fb_planesize);
336
337 if (flag == START_CURSOROPT || flag == END_CURSOROPT)
338 return;
339
340 /* if drawing into an overlay plane, don't xor, clr and set */
341 if (fb->fb_z > fb->disp_z)
342 {
343 opclr = RR_CLEAR; opset = RR_COPY;
344 }
345 else
346 {
347 opclr = opset = RR_XOR;
348 }
349
350 if (flag != DRAW_CURSOR)
351 {
352 /* erase it */
353 cc_8n_windowmove (ip->cursor, 0, 0, 1,
354 ovplane, fb->fb_x + ip->cursorx * ip->ftwidth,
355 fb->fb_y + ip->cursory * ip->ftheight,
356 fb->fb_width >> 3,
357 ip->ftheight, ip->ftwidth, opclr);
358 }
359 if (flag == DRAW_CURSOR || flag == MOVE_CURSOR)
360 {
361 /* draw it */
362 int newx = MIN(ip->curx, ip->cols - 1);
363 cc_8n_windowmove (ip->cursor, 0, 0, 1,
364 ovplane, fb->fb_x + newx * ip->ftwidth,
365 fb->fb_y + ip->cury * ip->ftheight,
366 fb->fb_width >> 3,
367 ip->ftheight, ip->ftwidth, opset);
368 ip->cursorx = newx;
369 ip->cursory = ip->cury;
370 }
371 }
372
373 static void
374 cc_8n_putc(ip, c, dy, dx, mode)
375 register struct ite_softc *ip;
376 register int dy, dx;
377 int c, mode;
378 {
379 register int wrr = ((mode == ATTR_INV) ? RR_COPYINVERTED : RR_COPY);
380 struct ccite *cci = (struct ccite *) ip->priv;
381 struct ccfb *fb = cci->fb;
382
383 if (c >= ip->font_lo && c <= ip->font_hi)
384 {
385 c -= ip->font_lo;
386
387 cc_8n_windowmove (ip->font, 0, c * ip->ftheight, 1,
388 cci->buf_rows[dy].buf,
389 dx * ip->ftwidth, 0, fb->fb_width >> 3,
390 ip->ftheight, ip->ftwidth, wrr);
391 }
392 }
393
394 static void
395 cc_8n_clear(ip, sy, sx, h, w)
396 struct ite_softc *ip;
397 register int sy, sx, h, w;
398 {
399 struct ccite *cci = (struct ccite *) ip->priv;
400 struct ccfb *fb = cci->fb;
401 int y;
402
403 for (y = sy; y < sy + h; y++)
404 cc_8n_windowmove (0, 0, 0, 0,
405 cci->buf_rows[y].buf, sx * ip->ftwidth, 0,
406 fb->fb_width >> 3,
407 ip->ftheight, w * ip->ftwidth, RR_CLEAR);
408 }
409
410 /* Note: sx is only relevant for SCROLL_LEFT or SCROLL_RIGHT. */
411 static void
412 cc_8n_scroll(ip, sy, sx, count, dir)
413 register struct ite_softc *ip;
414 register int sy;
415 int dir, sx, count;
416 {
417 struct ccite *cci = (struct ccite *) ip->priv;
418
419 if (dir == SCROLL_UP)
420 {
421 int dy = sy - count;
422 int bot = ip->inside_margins ? ip->bottom_margin : ip->rows - 1;
423 int height = bot - sy + 1;
424 int i;
425
426 for (i = 0; i < height; i++)
427 swap_rows(ip, sy + i, dy + i);
428 }
429 else if (dir == SCROLL_DOWN)
430 {
431 int dy = sy + count;
432 int bot = ip->inside_margins ? ip->bottom_margin : ip->rows - 1;
433 int height = bot - dy + 1;
434 int i;
435
436 for (i = (height - 1); i >= 0; i--)
437 swap_rows(ip, sy + i, dy + i);
438 }
439 else if (dir == SCROLL_RIGHT)
440 {
441 struct ccfb *fb = cci->fb;
442
443 cc_8n_cursor(ip, ERASE_CURSOR);
444 cc_8n_windowmove(cci->buf_rows[sy].buf,
445 sx * ip->ftwidth, 0, fb->fb_width >> 3,
446 cci->buf_rows[sy].buf,
447 (sx + count) * ip->ftwidth, 0, fb->fb_width >> 3,
448 ip->ftheight, (ip->cols - (sx + count)) * ip->ftwidth, RR_COPY);
449 }
450 else
451 {
452 struct ccfb *fb = cci->fb;
453
454 cc_8n_cursor(ip, ERASE_CURSOR);
455 cc_8n_windowmove(cci->buf_rows[sy].buf,
456 sx * ip->ftwidth, 0, fb->fb_width >> 3,
457 cci->buf_rows[sy].buf,
458 (sx - count) * ip->ftwidth, 0, fb->fb_width >> 3,
459 ip->ftheight, (ip->cols - sx) * ip->ftwidth, RR_COPY);
460 }
461 }
462
463
464
465 /*** (M<8)-by-N routines ***/
466
467 /* NOTE: This routine assumes a cursor overlay plane,
468 but it does allow cursors up to 32 pixels wide. */
469 static void
470 cc_le32n_cursor(struct ite_softc *ip, int flag)
471 {
472 struct ccite *cci = (struct ccite *) ip->priv;
473 struct ccfb *fb = cci->fb;
474 /* the cursor is always drawn in the last plane */
475 unsigned char *ovplane, opclr, opset;
476
477 if (flag == START_CURSOROPT || flag == END_CURSOROPT)
478 return;
479
480 ovplane = fb->fb + (fb->fb_z - 1) * (fb->fb_planesize);
481
482 if (flag != DRAW_CURSOR)
483 {
484 /* erase the cursor */
485 u_char *pl = ovplane + ((fb->fb_y + ip->cursory * ip->ftheight) * (fb->fb_width >> 3));
486 int ofs = fb->fb_x + ip->cursorx * ip->ftwidth;
487 int h;
488
489 for (h = ip->ftheight-1; h >= 0; h--)
490 {
491 asm("bfclr %0@{%1:%2}"
492 : : "a" (pl), "d" (ofs), "d" (ip->ftwidth));
493 pl += fb->fb_width >> 3;
494 }
495 }
496 if (flag == DRAW_CURSOR || flag == MOVE_CURSOR)
497 {
498 u_char *pl;
499 int ofs, h;
500
501 /* store the position */
502 ip->cursorx = MIN(ip->curx, ip->cols-1);
503 ip->cursory = ip->cury;
504
505 /* draw the cursor */
506 pl = ovplane + ((fb->fb_y + ip->cursory * ip->ftheight) * (fb->fb_width >> 3));
507 ofs = fb->fb_x + ip->cursorx * ip->ftwidth;
508
509 for (h = ip->ftheight-1; h >= 0; h--)
510 {
511 asm("bfset %0@{%1:%2}"
512 : : "a" (pl), "d" (ofs), "d" (ip->ftwidth));
513 pl += fb->fb_width >> 3;
514 }
515 }
516 }
517
518 static void
519 cc_le8n_putc(struct ite_softc *ip, int c, int dy, int dx, int mode)
520 {
521 if (c >= ip->font_lo && c <= ip->font_hi)
522 {
523 struct ccite *cci = (struct ccite *) ip->priv;
524 struct ccfb *fb = cci->fb;
525 u_char *pl = cci->buf_rows[dy].buf;
526 int ofs = dx * ip->ftwidth;
527 u_char *fontp = ip->font + (c - ip->font_lo) * ip->ftheight;
528 int h;
529
530 if (mode != ATTR_INV)
531 {
532 for (h = ip->ftheight-1; h >= 0; h--)
533 {
534 asm("bfins %3,%0@{%1:%2}"
535 : : "a" (pl), "d" (ofs), "d" (ip->ftwidth), "d" (*fontp++));
536 pl += fb->fb_width >> 3;
537 }
538 }
539 else
540 {
541 for (h = ip->ftheight-1; h >= 0; h--)
542 {
543 asm("bfins %3,%0@{%1:%2}"
544 : : "a" (pl), "d" (ofs), "d" (ip->ftwidth), "d" (~(*fontp++)));
545 pl += fb->fb_width >> 3;
546 }
547 }
548 }
549 }
550
551 static void
552 cc_le8n_clear(struct ite_softc *ip, int sy, int sx, int h, int w)
553 {
554 struct ccite *cci = (struct ccite *) ip->priv;
555 struct ccfb *fb = cci->fb;
556
557 if ((sx == 0) && (w == ip->cols))
558 {
559 /* common case: clearing whole lines */
560 while (h--)
561 {
562 bzero(cci->buf_rows[sy].buf, (fb->fb_width >> 3) * ip->ftheight);
563 sy++;
564 }
565 }
566 else
567 {
568 /* clearing only part of a line */
569 /* XXX could be optimized MUCH better, but is it worth the trouble? */
570 while (h--)
571 {
572 u_char *pl = cci->buf_rows[sy].buf;
573 int ofs = sx * ip->ftwidth;
574 int i, j;
575 for (i = w-1; i >= 0; i--)
576 {
577 u_char *ppl = pl;
578 for (j = ip->ftheight-1; j >= 0; j--)
579 {
580 asm("bfclr %0@{%1:%2}"
581 : : "a" (ppl), "d" (ofs), "d" (ip->ftwidth));
582 ppl += fb->fb_width >> 3;
583 }
584 ofs += ip->ftwidth;
585 }
586 sy++;
587 }
588 }
589 }
590
591 /* Note: sx is only relevant for SCROLL_LEFT or SCROLL_RIGHT. */
592 static void
593 cc_le8n_scroll(ip, sy, sx, count, dir)
594 register struct ite_softc *ip;
595 register int sy;
596 int dir, sx, count;
597 {
598 if (dir == SCROLL_UP)
599 {
600 int dy = sy - count;
601 int bot = ip->inside_margins ? ip->bottom_margin : ip->rows - 1;
602 int height = bot - sy + 1;
603 int i;
604
605 for (i = 0; i < height; i++)
606 swap_rows(ip, sy + i, dy + i);
607 }
608 else if (dir == SCROLL_DOWN)
609 {
610 int dy = sy + count;
611 int bot = ip->inside_margins ? ip->bottom_margin : ip->rows - 1;
612 int height = bot - dy + 1;
613 int i;
614
615 for (i = (height - 1); i >= 0; i--)
616 swap_rows(ip, sy + i, dy + i);
617 }
618 else if (dir == SCROLL_RIGHT)
619 {
620 struct ccite *cci = (struct ccite *) ip->priv;
621 struct ccfb *fb = cci->fb;
622 u_char *pl = cci->buf_rows[sy].buf;
623 int sofs = (ip->cols - count) * ip->ftwidth;
624 int dofs = (ip->cols) * ip->ftwidth;
625 int i, j;
626
627 cc_le32n_cursor(ip, ERASE_CURSOR);
628 for (j = ip->ftheight-1; j >= 0; j--)
629 {
630 int sofs2 = sofs, dofs2 = dofs;
631 for (i = (ip->cols - (sx + count))-1; i >= 0; i--)
632 {
633 int t;
634 sofs2 -= ip->ftwidth;
635 dofs2 -= ip->ftwidth;
636 asm("bfextu %1@{%2:%3},%0"
637 : "=d" (t)
638 : "a" (pl), "d" (sofs2), "d" (ip->ftwidth));
639 asm("bfins %3,%0@{%1:%2}"
640 : : "a" (pl), "d" (dofs2), "d" (ip->ftwidth), "d" (t));
641 }
642 pl += fb->fb_width >> 3;
643 }
644 }
645 else /* SCROLL_LEFT */
646 {
647 struct ccite *cci = (struct ccite *) ip->priv;
648 struct ccfb *fb = cci->fb;
649 u_char *pl = cci->buf_rows[sy].buf;
650 int sofs = (sx) * ip->ftwidth;
651 int dofs = (sx - count) * ip->ftwidth;
652 int i, j;
653
654 cc_le32n_cursor(ip, ERASE_CURSOR);
655 for (j = ip->ftheight-1; j >= 0; j--)
656 {
657 int sofs2 = sofs, dofs2 = dofs;
658 for (i = (ip->cols - sx)-1; i >= 0; i--)
659 {
660 int t;
661 asm("bfextu %1@{%2:%3},%0"
662 : "=d" (t)
663 : "a" (pl), "d" (sofs2), "d" (ip->ftwidth));
664 asm("bfins %3,%0@{%1:%2}"
665 : : "a" (pl), "d" (dofs2), "d" (ip->ftwidth), "d" (t));
666 sofs2 += ip->ftwidth;
667 dofs2 += ip->ftwidth;
668 }
669 pl += fb->fb_width >> 3;
670 }
671 }
672 }
673
674 #endif
675