summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2006-08-23 17:30:51 +0000
committerJens Arnold <amiconn@rockbox.org>2006-08-23 17:30:51 +0000
commit9af13c327e3a086f8015aec8135e01018a7ffb2b (patch)
tree65a91acf8b9e5dc4b8765c8949859f8961e3c4a0
parentd5fe8030baccc17d22c3ecdf2d4af77b71e41c82 (diff)
downloadrockbox-9af13c327e3a086f8015aec8135e01018a7ffb2b.tar.gz
rockbox-9af13c327e3a086f8015aec8135e01018a7ffb2b.zip
H300: * Assembler optimised lcd_yuv_blit(), based on the X5 version. 23..31% speedup in tests depending on video size. * Don't set HORIZ_RAM_ADDR_POS for LCD updates, it's unnecessary. * Started the target tree move for H300 with this.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10724 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/SOURCES6
-rw-r--r--firmware/drivers/lcd-h300.c179
-rwxr-xr-xfirmware/drivers/lcd.S95
-rwxr-xr-xfirmware/target/coldfire/iriver/h300/lcd-as-h300.S385
4 files changed, 438 insertions, 227 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 63cbf9c56f..e56199658c 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -179,7 +179,7 @@ thread.c
179timer.c 179timer.c
180crt0.S 180crt0.S
181drivers/lcd.S 181drivers/lcd.S
182#endif 182#endif
183mp3_playback.c 183mp3_playback.c
184mp3data.c 184mp3data.c
185#if CONFIG_CODEC != SWCODEC 185#if CONFIG_CODEC != SWCODEC
@@ -251,6 +251,10 @@ target/coldfire/iaudio/x5/lcd-remote-x5.c
251#endif 251#endif
252#endif 252#endif
253 253
254#ifdef IRIVER_H300_SERIES
255target/coldfire/iriver/h300/lcd-as-h300.S
256#endif
257
254#ifdef IRIVER_H10 258#ifdef IRIVER_H10
255#ifndef SIMULATOR 259#ifndef SIMULATOR
256target/arm/iriver/h10/backlight-h10.c 260target/arm/iriver/h10/backlight-h10.c
diff --git a/firmware/drivers/lcd-h300.c b/firmware/drivers/lcd-h300.c
index c3f5d48f87..41d2d11509 100644
--- a/firmware/drivers/lcd-h300.c
+++ b/firmware/drivers/lcd-h300.c
@@ -301,134 +301,59 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
301 /*if(display_on)*/ 301 /*if(display_on)*/
302} 302}
303 303
304#define CSUB_X 2 304/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420.
305#define CSUB_Y 2 305 * y should have two lines of Y back to back.
306 306 * bu and rv should contain the Cb and Cr data for the two lines of Y.
307#define RYFAC (31*257) 307 * Stores bu, guv and rv in repective buffers for use in second line.
308#define GYFAC (63*257) 308 */
309#define BYFAC (31*257) 309extern void lcd_write_yuv420_lines(const unsigned char *y,
310#define RVFAC 11170 /* 31 * 257 * 1.402 */ 310 unsigned char *bu, unsigned char *guv, unsigned char *rv, int width);
311#define GVFAC (-11563) /* 63 * 257 * -0.714136 */ 311
312#define GUFAC (-5572) /* 63 * 257 * -0.344136 */ 312/* Performance function to blit a YUV bitmap directly to the LCD
313#define BUFAC 14118 /* 31 * 257 * 1.772 */ 313 * src_x, src_y, width and height should be even
314 314 * x, y, width and height have to be within LCD bounds
315#define ROUNDOFFS (127*257) 315 */
316
317/* Performance function to blit a YUV bitmap directly to the LCD */
318void lcd_yuv_blit(unsigned char * const src[3], 316void lcd_yuv_blit(unsigned char * const src[3],
319 int src_x, int src_y, int stride, 317 int src_x, int src_y, int stride,
320 int x, int y, int width, int height) 318 int x, int y, int width, int height)
321{ 319{
322 if (display_on) 320 /* IRAM Y, Cb/bu, guv and Cb/rv buffers. */
323 { 321 unsigned char y_ibuf[LCD_WIDTH*2];
324 int ymax; 322 unsigned char bu_ibuf[LCD_WIDTH/2];
325 323 unsigned char guv_ibuf[LCD_WIDTH/2];
326 width = (width + 1) & ~1; 324 unsigned char rv_ibuf[LCD_WIDTH/2];
327 height = (height + 1) & ~1; 325 const unsigned char *ysrc, *usrc, *vsrc;
328 ymax = y + height - 1; 326 const unsigned char *ysrc_max;
329
330 /* set update window */
331
332 /* horiz ram addr */
333 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (ymax << 8) | y);
334
335 /* vert ram addr */
336 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset));
337 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
338 lcd_begin_write_gram();
339 327
340 for (; y <= ymax; y++) 328 if (!display_on)
341 { 329 return;
342 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ 330
343 const unsigned char *ysrc = src[0] + stride * src_y + src_x; 331 width &= ~1; /* stay on the safe side */
344 const unsigned char *usrc = src[1] + (stride/CSUB_X) * (src_y/CSUB_Y) 332 height &= ~1;
345 + (src_x/CSUB_X); 333
346 const unsigned char *vsrc = src[2] + (stride/CSUB_X) * (src_y/CSUB_Y) 334 /* Set start position and window */
347 + (src_x/CSUB_X); 335 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset));
348 const unsigned char *row_end = ysrc + width; 336 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
349 337
350 int y, u, v; 338 lcd_begin_write_gram();
351 int rc, gc, bc; 339
352 int red, green, blue; 340 ysrc = src[0] + src_y * stride + src_x;
353 unsigned rbits, gbits, bbits; 341 usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1);
354 342 vsrc = src[2] + (src_y * stride >> 2) + (src_x >> 1);
355 do 343 ysrc_max = ysrc + height * stride;
356 { 344
357 u = *usrc++ - 128; 345 do
358 v = *vsrc++ - 128; 346 {
359 rc = RVFAC * v + ROUNDOFFS; 347 memcpy(y_ibuf, ysrc, width);
360 gc = GVFAC * v + GUFAC * u + ROUNDOFFS; 348 memcpy(y_ibuf + width, ysrc + stride, width);
361 bc = BUFAC * u + ROUNDOFFS; 349 memcpy(bu_ibuf, usrc, width >> 1);
362 350 memcpy(rv_ibuf, vsrc, width >> 1);
363 y = *ysrc++; 351 lcd_write_yuv420_lines(y_ibuf, bu_ibuf, guv_ibuf, rv_ibuf, width);
364 red = RYFAC * y + rc; 352 ysrc += 2 * stride;
365 green = GYFAC * y + gc; 353 usrc += stride >> 1;
366 blue = BYFAC * y + bc; 354 vsrc += stride >> 1;
367
368 if ((unsigned)red > (RYFAC*255+ROUNDOFFS))
369 {
370 if (red < 0)
371 red = 0;
372 else
373 red = (RYFAC*255+ROUNDOFFS);
374 }
375 if ((unsigned)green > (GYFAC*255+ROUNDOFFS))
376 {
377 if (green < 0)
378 green = 0;
379 else
380 green = (GYFAC*255+ROUNDOFFS);
381 }
382 if ((unsigned)blue > (BYFAC*255+ROUNDOFFS))
383 {
384 if (blue < 0)
385 blue = 0;
386 else
387 blue = (BYFAC*255+ROUNDOFFS);
388 }
389 rbits = ((unsigned)red) >> 16 ;
390 gbits = ((unsigned)green) >> 16 ;
391 bbits = ((unsigned)blue) >> 16 ;
392
393 LCD_DATA = (rbits << 11) | (gbits << 5) | bbits;
394
395 y = *ysrc++;
396 red = RYFAC * y + rc;
397 green = GYFAC * y + gc;
398 blue = BYFAC * y + bc;
399
400 if ((unsigned)red > (RYFAC*255+ROUNDOFFS))
401 {
402 if (red < 0)
403 red = 0;
404 else
405 red = (RYFAC*255+ROUNDOFFS);
406 }
407 if ((unsigned)green > (GYFAC*255+ROUNDOFFS))
408 {
409 if (green < 0)
410 green = 0;
411 else
412 green = (GYFAC*255+ROUNDOFFS);
413 }
414 if ((unsigned)blue > (BYFAC*255+ROUNDOFFS))
415 {
416 if (blue < 0)
417 blue = 0;
418 else
419 blue = (BYFAC*255+ROUNDOFFS);
420 }
421 rbits = ((unsigned)red) >> 16 ;
422 gbits = ((unsigned)green) >> 16 ;
423 bbits = ((unsigned)blue) >> 16 ;
424
425 LCD_DATA = (rbits << 11) | (gbits << 5) | bbits;
426 }
427 while (ysrc < row_end);
428
429 src_y++;
430 }
431 } 355 }
356 while (ysrc < ysrc_max);
432} 357}
433 358
434/* Update the display. 359/* Update the display.
@@ -438,10 +363,6 @@ void lcd_update(void)
438{ 363{
439 if(display_on){ 364 if(display_on){
440 /* reset update window */ 365 /* reset update window */
441 /* horiz ram addr: 0 - 175 */
442 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0xaf00);
443
444 /* vert ram addr: 0 - 219 */
445 lcd_write_reg(R_VERT_RAM_ADDR_POS,((xoffset+219)<<8) | xoffset); 366 lcd_write_reg(R_VERT_RAM_ADDR_POS,((xoffset+219)<<8) | xoffset);
446 367
447 /* Copy display bitmap to hardware */ 368 /* Copy display bitmap to hardware */
@@ -467,15 +388,11 @@ void lcd_update_rect(int x, int y, int width, int height)
467 388
468 /* set update window */ 389 /* set update window */
469 390
470 /* horiz ram addr */
471 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (ymax << 8) | y);
472
473 /* vert ram addr */
474 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset)); 391 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset));
475 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y); 392 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
476 lcd_begin_write_gram(); 393 lcd_begin_write_gram();
477 394
478 /* Copy specified rectangle bitmap to hardware */ 395 /* Copy specified rectangle bitmap to hardware */
479 for (; y <= ymax; y++) 396 for (; y <= ymax; y++)
480 { 397 {
481 lcd_write_data ((unsigned short *)&lcd_framebuffer[y][x], width); 398 lcd_write_data ((unsigned short *)&lcd_framebuffer[y][x], width);
diff --git a/firmware/drivers/lcd.S b/firmware/drivers/lcd.S
index 8764d793c3..d9e7092c94 100755
--- a/firmware/drivers/lcd.S
+++ b/firmware/drivers/lcd.S
@@ -371,99 +371,4 @@ lcd_write_data:
371 nop /* 1(0/0) */ 371 nop /* 1(0/0) */
372 bne .loop /* 2(0/0) */ 372 bne .loop /* 2(0/0) */
373 rts 373 rts
374#elif defined(IRIVER_H300_SERIES)
375 .section .icode,"ax",@progbits
376
377 .align 2
378 .global lcd_write_data
379 .type lcd_write_data,@function
380
381lcd_write_data:
382 move.l (4,%sp),%a0 /* data pointer */
383 move.l (8,%sp),%d0 /* length in words */
384 add.l %d0,%d0 /* words -> bytes */
385 add.l %a0,%d0 /* -> end address */
386 lea.l 0xf0000002,%a1 /* LCD data port */
387
388 move.l %a0,%d1
389 btst.l #1,%d1 /* already longword aligned? */
390 beq.b .word1_end /* yes: skip initial word copy */
391
392 move.w (%a0)+,(%a1) /* transfer initial word */
393
394.word1_end: /* now longword aligned */
395 moveq.l #28,%d1
396 add.l %a0,%d1
397 and.l #0xFFFFFFF0,%d1 /* %d1 = first line bound + 16 */
398 cmp.l %d1,%d0 /* at least one full line to send? */
399 blo.b .long2_start /* no: skip to trailing longword handling */
400
401 lea.l (-16,%sp),%sp /* free up some registers */
402 movem.l %d2-%d4/%a2,(%sp)
403
404 subq.l #8,%d1
405 subq.l #8,%d1 /* %d1 = first line bound */
406
407 cmp.l %a0,%d1 /* any leading longwords? */
408 bls.b .long1_end /* no: skip leading long loop */
409
410.long1_loop:
411 move.l (%a0)+,%d2 /* read longword */
412 swap %d2 /* send data to LCD in correct order...*/
413 move.w %d2,(%a1)
414 swap %d2
415 move.w %d2,(%a1)
416 cmp.l %a0,%d1 /* run %a0 up to first line bound */
417 bhi.b .long1_loop
418
419.long1_end:
420 move.l %d0,%a2
421 lea.l (-14,%a2),%a2 /* %a2 = end address - 14 (one line/pass) */
422
423 /* burst-optimised line transfers */
424.line_loop:
425 movem.l (%a0),%d1-%d4 /* burst-read line */
426 lea.l (16,%a0),%a0 /* increment address */
427 swap %d1 /* send data to LCD in correct order... */
428 move.w %d1,(%a1)
429 swap %d1
430 move.w %d1,(%a1)
431 swap %d2
432 move.w %d2,(%a1)
433 swap %d2
434 move.w %d2,(%a1)
435 swap %d3
436 move.w %d3,(%a1)
437 swap %d3
438 move.w %d3,(%a1)
439 swap %d4
440 move.w %d4,(%a1)
441 swap %d4
442 move.w %d4,(%a1)
443 cmp.l %a0,%a2 /* run %a0 up to last line bound */
444 bhi.b .line_loop
445
446 movem.l (%sp),%d2-%d4/%a2
447 lea.l (16,%sp),%sp /* restore registers */
448
449.long2_start:
450 subq.l #2,%d0 /* account for handling 2 words per loop */
451 cmp.l %a0,%d0 /* any (trailing longwords? */
452 bls.b .long2_end /* no: skip trailing longword loop */
453
454.long2_loop:
455 move.l (%a0)+,%d1 /* read longword */
456 swap %d1 /* send data to LCD in correct order */
457 move.w %d1,(%a1)
458 swap %d1
459 move.w %d1,(%a1)
460 cmp.l %a0,%d0 /* run %a0 up to last long bound */
461 bhi.b .long2_loop
462
463.long2_end:
464 blo.b .word2_end /* no final word: skip */
465 move.w (%a0)+,(%a1) /* transfer final word */
466
467.word2_end:
468 rts
469#endif 374#endif
diff --git a/firmware/target/coldfire/iriver/h300/lcd-as-h300.S b/firmware/target/coldfire/iriver/h300/lcd-as-h300.S
new file mode 100755
index 0000000000..c6c1c76136
--- /dev/null
+++ b/firmware/target/coldfire/iriver/h300/lcd-as-h300.S
@@ -0,0 +1,385 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Jens Arnold
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "config.h"
21#include "cpu.h"
22
23 .section .icode, "ax", @progbits
24
25 .align 2
26 .global lcd_write_data
27 .type lcd_write_data, @function
28
29lcd_write_data:
30 move.l (4, %sp), %a0 /* data pointer */
31 move.l (8, %sp), %d0 /* length in words */
32 add.l %d0, %d0 /* words -> bytes */
33 add.l %a0, %d0 /* -> end address */
34 lea.l 0xf0000002, %a1 /* LCD data port */
35
36 move.l %a0, %d1
37 btst.l #1, %d1 /* already longword aligned? */
38 beq.s .word1_end /* yes: skip initial word copy */
39
40 move.w (%a0)+, (%a1) /* transfer initial word */
41
42.word1_end: /* now longword aligned */
43 moveq.l #28, %d1
44 add.l %a0, %d1
45 and.l #0xFFFFFFF0,%d1 /* %d1 = first line bound + 16 */
46 cmp.l %d1, %d0 /* at least one full line to send? */
47 blo.s .long2_start /* no: skip to trailing longword handling */
48
49 lea.l (-16, %sp), %sp /* free up some registers */
50 movem.l %d2-%d4/%a2, (%sp)
51
52 subq.l #8, %d1
53 subq.l #8, %d1 /* %d1 = first line bound */
54
55 cmp.l %a0, %d1 /* any leading longwords? */
56 bls.s .long1_end /* no: skip leading long loop */
57
58.long1_loop:
59 move.l (%a0)+, %d2 /* read longword */
60 swap %d2 /* send data to LCD in correct order...*/
61 move.w %d2, (%a1)
62 swap %d2
63 move.w %d2, (%a1)
64 cmp.l %a0, %d1 /* run %a0 up to first line bound */
65 bhi.s .long1_loop
66
67.long1_end:
68 move.l %d0, %a2
69 lea.l (-14, %a2), %a2 /* %a2 = end address - 14 (one line/pass) */
70
71 /* burst-optimised line transfers */
72.line_loop:
73 movem.l (%a0), %d1-%d4 /* burst-read line */
74 lea.l (16, %a0), %a0 /* increment address */
75 swap %d1 /* send data to LCD in correct order... */
76 move.w %d1, (%a1)
77 swap %d1
78 move.w %d1, (%a1)
79 swap %d2
80 move.w %d2, (%a1)
81 swap %d2
82 move.w %d2, (%a1)
83 swap %d3
84 move.w %d3, (%a1)
85 swap %d3
86 move.w %d3, (%a1)
87 swap %d4
88 move.w %d4, (%a1)
89 swap %d4
90 move.w %d4, (%a1)
91 cmp.l %a0, %a2 /* run %a0 up to last line bound */
92 bhi.s .line_loop
93
94 movem.l (%sp), %d2-%d4/%a2
95 lea.l (16, %sp), %sp /* restore registers */
96
97.long2_start:
98 subq.l #2, %d0 /* account for handling 2 words per loop */
99 cmp.l %a0, %d0 /* any (trailing longwords? */
100 bls.s .long2_end /* no: skip trailing longword loop */
101
102.long2_loop:
103 move.l (%a0)+, %d1 /* read longword */
104 swap %d1 /* send data to LCD in correct order */
105 move.w %d1, (%a1)
106 swap %d1
107 move.w %d1, (%a1)
108 cmp.l %a0, %d0 /* run %a0 up to last long bound */
109 bhi.s .long2_loop
110
111.long2_end:
112 blo.s .word2_end /* no final word: skip */
113 move.w (%a0)+, (%a1) /* transfer final word */
114
115.word2_end:
116 rts
117.lcd_write_data_end:
118 .size lcd_write_data, .lcd_write_data_end - lcd_write_data
119
120
121/* lcd_write_yuv420_lines(), based on lcd-as-x5.S
122 *
123 * See http://en.wikipedia.org/wiki/YCbCr
124 * ITU-R BT.601 (formerly CCIR 601):
125 * |Y'| | 0.299000 0.587000 0.114000| |R|
126 * |Pb| = |-0.168736 -0.331264 0.500000| |G| or 0.564334*(B - Y')
127 * |Pr| | 0.500000 -0.418688 0.081312| |B| or 0.713267*(R - Y')
128 * Scaled, normalized and rounded:
129 * |Y'| | 65 129 25| |R| + 16 : 16->235
130 * |Cb| = |-38 -74 112| |G| + 128 : 16->240
131 * |Cr| |112 -94 -18| |B| + 128 : 16->240
132 *
133 * The inverse:
134 * |R| |1.000000 0.000000 1.402000| |Y'|
135 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
136 * |B| |1.000000 1.772000 0.000000| |Pr|
137 * Scaled, normalized, rounded and tweaked to yield RGB666, as converting
138 * directly to RGB565 gives too much roundoff error:
139 * |R| |74 0 101| |Y' - 16| / 256
140 * |G| = |74 -24 -51| |Cb - 128| / 256
141 * |B| |74 128 0| |Cr - 128| / 256
142 */
143
144 .align 2
145 .global lcd_write_yuv420_lines
146 .type lcd_write_yuv420_lines, @function
147
148lcd_write_yuv420_lines:
149 lea.l (-36, %sp), %sp /* free up some registers */
150 movem.l %d2-%d6/%a2-%a5, (%sp)
151
152 lea.l 0xf0000002, %a0 /* LCD data port */
153 movem.l (36+4, %sp), %a1-%a5 /* Y data, Cb data, guv storage, Cr data, width */
154 lea.l (%a1, %a5), %a5 /* end address */
155
156.yuv_line_loop1:
157 /* chroma for first & second pixel */
158 clr.l %d1 /* load bu component */
159 move.b (%a2), %d1
160 clr.l %d3 /* load rv component */
161 move.b (%a4), %d3
162 moveq.l #-128, %d0
163 add.l %d0, %d1
164 add.l %d0, %d3
165
166 move.l %d1, %d2 /* %d2 = cb component for guv */
167 asr.l #1, %d1 /* %d1 = 128 * (Cb - 128) / 256 */
168 move.b %d1, (%a2)+ /* save bu for next line */
169 moveq.l #-24, %d0
170 muls.w %d0, %d2 /* %d2 = -24 * (Cb - 128)*/
171 moveq.l #-51, %d0
172 muls.w %d3, %d0
173 add.l %d0, %d2 /* %d2 = -24 * (Cb - 128) - 51 * (Cr - 128) */
174 asr.l #8, %d2
175 move.b %d2, (%a3)+ /* save guv for next line */
176 moveq.l #101, %d0
177 muls.w %d0, %d3 /* %d3 = 101 * (Cr - 128) */
178 asr.l #8, %d3
179 move.b %d3, (%a4)+ /* save rv for next line */
180
181 /* luma for first pixel */
182 clr.l %d4 /* load y component */
183 move.b (%a1)+, %d4
184 moveq.l #74, %d0
185 muls.w %d0, %d4 /* %d4 = 36 * Y */
186 asr.l #8, %d4
187 subq.l #4, %d4 /* correction for (Y - 16) and rounding */
188 move.l %d4, %d5
189 move.l %d4, %d6
190
191 /* combine & write first pixel */
192 add.l %d1, %d4 /* %d4 = blue */
193 add.l %d2, %d5 /* %d5 = green */
194 add.l %d3, %d6 /* %d6 = red */
195
196 move.l %d4, %d0 /* clamping */
197 or.l %d5, %d0
198 or.l %d6, %d0
199 asr.l #6, %d0
200 beq.s .yuv_all_ok1
201 moveq.l #63, %d0
202 cmp.l %d0, %d4
203 bls.s .yuv_blue_ok1
204 spl.b %d4
205 and.l %d0, %d4
206.yuv_blue_ok1:
207 cmp.l %d0, %d5
208 bls.s .yuv_green_ok1
209 spl.b %d5
210 and.l %d0, %d5
211.yuv_green_ok1:
212 cmp.l %d0, %d6
213 bls.s .yuv_red_ok1
214 spl.b %d6
215 and.l %d0, %d6
216.yuv_red_ok1:
217.yuv_all_ok1:
218
219 lsr.l #1, %d6 /* pack, convert to RGB565 and output */
220 lsr.l #1, %d4
221 lsl.l #6, %d6
222 or.l %d6, %d5
223 lsl.l #5, %d5
224 or.l %d5, %d4
225 move.w %d4, (%a0)
226
227 /* luma for second pixel */
228 clr.l %d4 /* load y component */
229 move.b (%a1)+, %d4
230 moveq.l #74, %d0
231 muls.w %d0, %d4 /* %d4 = 36 * Y */
232 asr.l #8, %d4
233 subq.l #4, %d4 /* correction for (Y - 16) and rounding */
234
235 /* combine & write second pixel */
236 add.l %d4, %d1 /* %d1 = blue */
237 add.l %d4, %d2 /* %d2 = green */
238 add.l %d4, %d3 /* %d3 = red */
239
240 move.l %d1, %d0 /* clamping */
241 or.l %d2, %d0
242 or.l %d3, %d0
243 asr.l #6, %d0
244 beq.s .yuv_all_ok2
245 moveq.l #63, %d0
246 cmp.l %d0, %d1
247 bls.s .yuv_blue_ok2
248 spl.b %d1
249 and.l %d0, %d1
250.yuv_blue_ok2:
251 cmp.l %d0, %d2
252 bls.s .yuv_green_ok2
253 spl.b %d2
254 and.l %d0, %d2
255.yuv_green_ok2:
256 cmp.l %d0, %d3
257 bls.s .yuv_red_ok2
258 spl.b %d3
259 and.l %d0, %d3
260.yuv_red_ok2:
261.yuv_all_ok2:
262
263 lsr.l #1, %d3 /* pack, convert to RGB565 and output */
264 lsr.l #1, %d1
265 lsl.l #6, %d3
266 or.l %d3, %d2
267 lsl.l #5, %d2
268 or.l %d2, %d1
269 move.w %d1, (%a0)
270
271 cmp.l %a1,%a5 /* run %a1 up to end of line */
272 bhi.w .yuv_line_loop1
273
274 /* Rewind chroma pointers */
275 movem.l (36+8, %sp), %a2-%a5 /* bu data, guv data, rv data, width */
276 lea.l (%a1, %a5), %a5 /* next end address */
277
278.yuv_line_loop2:
279 /* read saved chromas and sign extend */
280 move.b (%a2)+, %d1
281 extb.l %d1
282 move.b (%a3)+, %d2
283 extb.l %d2
284 move.b (%a4)+, %d3
285 extb.l %d3
286
287 /* luma for first pixel */
288 clr.l %d4 /* load y component */
289 move.b (%a1)+, %d4
290 moveq.l #74, %d0
291 muls.w %d0, %d4 /* %d4 = 36 * Y */
292 asr.l #8, %d4
293 subq.l #4, %d4 /* correction for (Y - 16) and rounding */
294 move.l %d4, %d5
295 move.l %d4, %d6
296
297 /* combine & write first pixel */
298 add.l %d1, %d4 /* %d4 = blue */
299 add.l %d2, %d5 /* %d5 = green */
300 add.l %d3, %d6 /* %d6 = red */
301
302 move.l %d4, %d0 /* clamping */
303 or.l %d5, %d0
304 or.l %d6, %d0
305 asr.l #6, %d0
306 beq.s .yuv_all_ok3
307 moveq.l #63, %d0
308 cmp.l %d0, %d4
309 bls.s .yuv_blue_ok3
310 spl.b %d4
311 and.l %d0, %d4
312.yuv_blue_ok3:
313 cmp.l %d0, %d5
314 bls.s .yuv_green_ok3
315 spl.b %d5
316 and.l %d0, %d5
317.yuv_green_ok3:
318 cmp.l %d0, %d6
319 bls.s .yuv_red_ok3
320 spl.b %d6
321 and.l %d0, %d6
322.yuv_red_ok3:
323.yuv_all_ok3:
324
325 lsr.l #1, %d6 /* pack, convert to RGB565 and output */
326 lsr.l #1, %d4
327 lsl.l #6, %d6
328 or.l %d6, %d5
329 lsl.l #5, %d5
330 or.l %d5, %d4
331 move.w %d4, (%a0)
332
333 /* luma for second pixel */
334 clr.l %d4 /* load y component */
335 move.b (%a1)+, %d4
336 moveq.l #74, %d0
337 muls.w %d0, %d4 /* %d4 = 36 * Y */
338 asr.l #8, %d4
339 subq.l #4, %d4 /* correction for (Y - 16) and rounding */
340
341 /* combine & write second pixel */
342 add.l %d4, %d1 /* %d1 = blue */
343 add.l %d4, %d2 /* %d2 = green */
344 add.l %d4, %d3 /* %d3 = red */
345
346 move.l %d1, %d0 /* clamping */
347 or.l %d2, %d0
348 or.l %d3, %d0
349 asr.l #6, %d0
350 beq.s .yuv_all_ok4
351 moveq.l #63, %d0
352 cmp.l %d0, %d1
353 bls.s .yuv_blue_ok4
354 spl.b %d1
355 and.l %d0, %d1
356.yuv_blue_ok4:
357 cmp.l %d0, %d2
358 bls.s .yuv_green_ok4
359 spl.b %d2
360 and.l %d0, %d2
361.yuv_green_ok4:
362 cmp.l %d0, %d3
363 bls.s .yuv_red_ok4
364 spl.b %d3
365 and.l %d0, %d3
366.yuv_red_ok4:
367.yuv_all_ok4:
368
369 lsr.l #1, %d3 /* pack, convert to RGB565 and output */
370 lsr.l #1, %d1
371 lsl.l #6, %d3
372 or.l %d3, %d2
373 lsl.l #5, %d2
374 or.l %d2, %d1
375 move.w %d1, (%a0)
376
377 cmp.l %a1, %a5 /* run %a1 up to end of line */
378 bhi.w .yuv_line_loop2
379
380 movem.l (%sp), %d2-%d6/%a2-%a5
381 lea.l (36, %sp), %sp /* restore registers */
382
383 rts
384.lcd_write_yuv420_lines_end:
385 .size lcd_write_yuv420_lines, .lcd_write_yuv420_lines_end - lcd_write_yuv420_lines