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