H300, X5: Optimised lcd_yuv_blit(), using line-pair zig-zag writing to the LCD contro...
[Rockbox.git] / firmware / target / coldfire / iriver / h300 / lcd-as-h300.S
blob9106e22c1c2c1d6021a144c8c6781f7a836ae3f5
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  ****************************************************************************/
20 #include "config.h"
21 #include "cpu.h"
23     .section    .icode, "ax", @progbits
25 /* lcd_write_yuv420_lines()
26  *
27  * See http://en.wikipedia.org/wiki/YCbCr
28  *   ITU-R BT.601 (formerly CCIR 601):
29  *   |Y'|   | 0.299000  0.587000  0.114000| |R|
30  *   |Pb| = |-0.168736 -0.331264  0.500000| |G| or 0.564334*(B - Y')
31  *   |Pr|   | 0.500000 -0.418688  0.081312| |B| or 0.713267*(R - Y')
32  *   Scaled, normalized and rounded:
33  *   |Y'|   | 65  129   25| |R| +  16 : 16->235
34  *   |Cb| = |-38  -74  112| |G| + 128 : 16->240
35  *   |Cr|   |112  -94  -18| |B| + 128 : 16->240
36  *
37  *   The inverse:
38  *   |R|   |1.000000  0.000000  1.402000| |Y'|
39  *   |G| = |1.000000 -0.334136 -0.714136| |Pb|
40  *   |B|   |1.000000  1.772000  0.000000| |Pr|
41  *   Scaled, normalized, rounded and tweaked to yield RGB565:
42  *   |R|   |19611723        0  26881894| |Y' -  16| >> 27
43  *   |G| = |19611723 -6406711 -13692816| |Cb - 128| >> 26
44  *   |B|   |19611723 33976259         0| |Cr - 128| >> 27
45  *
46  * Needs EMAC set to saturated, signed integer mode.
47  *
48  * register usage:
49  *   %a0 - LCD data port
50  *   %a1 - Y pointer
51  *   %a2 - C pointer
52  *   %a3 - C width
53  *   %a4 - Y end address
54  *   %a5 - Y factor
55  *   %a6 - BU factor
56  *   %d0 - scratch
57  *   %d1 -     B, previous Y \ alternating
58  *   %d2 - U / B, previous Y /
59  *   %d3 - V / G
60  *   %d4 - R / output pixel
61  *   %d5 - GU factor
62  *   %d6 - GV factor
63  *   %d7 - RGB signed -> unsigned conversion mask
64  */
65     .align      2
66     .global     lcd_write_yuv420_lines
67     .type       lcd_write_yuv420_lines, @function
69 lcd_write_yuv420_lines:
70     lea.l   (-44, %sp), %sp         /* free up some registers */
71     movem.l %d2-%d7/%a2-%a6, (%sp)
72     
73     lea.l   0xf0000002, %a0         /* LCD data port */
74     movem.l (44+4, %sp), %a1-%a3    /* Y data, C data, C width */
75     lea.l   (%a1, %a3*2), %a4       /* Y end address */
77     move.l  #19611723, %a5          /* y factor */
78     move.l  #33976259, %a6          /* bu factor */
79     move.l  #-6406711, %d5          /* gu factor */
80     move.l  #-13692816, %d6         /* gv factor */
81     move.l  #0x8410, %d7            /* bitmask for signed->unsigned conversion
82                                      * of R, G and B within RGB565 at once */
84     /* chroma for first 2x2 pixel block */
85     clr.l   %d3                     /* load v component */
86     move.b  (%a2, %a3), %d3
87     clr.l   %d2                     /* load u component */
88     move.b  (%a2)+, %d2
89     moveq.l #-128, %d0
90     add.l   %d0, %d2
91     add.l   %d0, %d3
93     mac.l   %a6, %d2, %acc0         /* bu */
94     mac.l   %d5, %d2, %acc1         /* gu */
95     mac.l   %d6, %d3, %acc1         /* gv */
96     move.l  #26881894, %d0          /* rv factor */
97     mac.l   %d0, %d3, %acc2         /* rv */
99     /* luma for very first pixel (top left) */
100     clr.l   %d1
101     move.b  (%a1, %a3*2), %d1
102     moveq.l #-126, %d0
103     add.l   %d1, %d0                /* y' (-0.5 ... +0.5) */
104     mac.l   %a5, %d0, %acc0
105     mac.l   %a5, %d0, %acc1
106     mac.l   %a5, %d0, %acc2
108     bra.b   .yuv_line_entry
110 .yuv_line_loop:
111     /* chroma for 2x2 pixel block */
112     clr.l   %d3                     /* load v component */
113     move.b  (%a2, %a3), %d3
114     clr.l   %d2                     /* load u component */
115     move.b  (%a2)+, %d2
116     moveq.l #-128, %d0
117     add.l   %d0, %d2
118     add.l   %d0, %d3
120     mac.l   %a6, %d2, %acc0         /* bu */
121     mac.l   %d5, %d2, %acc1         /* gu */
122     mac.l   %d6, %d3, %acc1         /* gv */
123     move.l  #26881894, %d0          /* rv factor */
124     mac.l   %d0, %d3, %acc2         /* rv */
126     /* luma for first pixel (top left) */
127     clr.l   %d1
128     move.b  (%a1, %a3*2), %d1
129     moveq.l #-126, %d0
130     add.l   %d1, %d0                /* y' (-0.5 ... +0.5) */
131     mac.l   %a5, %d0, %acc0
132     mac.l   %a5, %d0, %acc1
133     mac.l   %a5, %d0, %acc2
135     move.w  %d4, (%a0)
136     /* LCD write is delayed one pixel to use it for filling the EMAC latency */
138     /* convert to RGB565, pack and output */
139 .yuv_line_entry:
140     moveq.l #27, %d0
141     move.l  %acc0, %d2
142     move.l  %acc1, %d3
143     move.l  %acc2, %d4
144     lsr.l   %d0, %d2
145     lsr.l   %d0, %d4
146     moveq.l #26, %d0
147     lsr.l   %d0, %d3
148     lsl.l   #6, %d4
149     or.l    %d3, %d4
150     lsl.l   #5, %d4
151     or.l    %d2, %d4
152     eor.l   %d7, %d4
154     /* luma for second pixel (bottom left) as delta from the first */
155     clr.l   %d2
156     move.b  (%a1)+, %d2
157     move.l  %d2, %d0
158     sub.l   %d1, %d0
159     mac.l   %a5, %d0, %acc0
160     mac.l   %a5, %d0, %acc1
161     mac.l   %a5, %d0, %acc2
163     move.w  %d4, (%a0)
164     /* LCD write is delayed one pixel to use it for filling the EMAC latency */
166     /* convert to RGB565, pack and output */
167     moveq.l #27, %d0
168     move.l  %acc0, %d1
169     move.l  %acc1, %d3
170     move.l  %acc2, %d4
171     lsr.l   %d0, %d1
172     lsr.l   %d0, %d4
173     moveq.l #26, %d0
174     lsr.l   %d0, %d3
175     lsl.l   #6, %d4
176     or.l    %d3, %d4
177     lsl.l   #5, %d4
178     or.l    %d1, %d4
179     eor.l   %d7, %d4
181     /* luma for third pixel (top right) as delta from the second */
182     clr.l   %d1
183     move.b  (%a1, %a3*2), %d1
184     move.l  %d1, %d0
185     sub.l   %d2, %d0
186     mac.l   %a5, %d0, %acc0
187     mac.l   %a5, %d0, %acc1
188     mac.l   %a5, %d0, %acc2
190     move.w  %d4, (%a0)
191     /* LCD write is delayed one pixel to use it for filling the EMAC latency */
193     /* convert to RGB565, pack and output */
194     moveq.l #27, %d0
195     move.l  %acc0, %d2
196     move.l  %acc1, %d3
197     move.l  %acc2, %d4
198     lsr.l   %d0, %d2
199     lsr.l   %d0, %d4
200     moveq.l #26, %d0
201     lsr.l   %d0, %d3
202     lsl.l   #6, %d4
203     or.l    %d3, %d4
204     lsl.l   #5, %d4
205     or.l    %d2, %d4
206     eor.l   %d7, %d4
208     /* luma for fourth pixel (bottom right) as delta from the third */
209     clr.l   %d2
210     move.b  (%a1)+, %d2
211     move.l  %d2, %d0
212     sub.l   %d1, %d0
213     mac.l   %a5, %d0, %acc0
214     mac.l   %a5, %d0, %acc1
215     mac.l   %a5, %d0, %acc2
217     move.w  %d4, (%a0)
218     /* LCD write is delayed one pixel to use it for filling the EMAC latency */
220     /* convert to RGB565, pack and output */
221     moveq.l #27, %d0
222     movclr.l %acc0, %d1
223     movclr.l %acc1, %d3
224     movclr.l %acc2, %d4
225     lsr.l   %d0, %d1
226     lsr.l   %d0, %d4
227     moveq.l #26, %d0
228     lsr.l   %d0, %d3
229     lsl.l   #6, %d4
230     or.l    %d3, %d4
231     lsl.l   #5, %d4
232     or.l    %d1, %d4
233     eor.l   %d7, %d4
235     cmp.l   %a1, %a4                /* run %a1 up to end of line */
236     bhi.w   .yuv_line_loop
238     move.w  %d4, (%a0)              /* write (very) last pixel */
240     movem.l (%sp), %d2-%d7/%a2-%a6
241     lea.l   (44, %sp), %sp          /* restore registers */
242     rts
243 .yuv_end:
244     .size   lcd_write_yuv420_lines, .yuv_end - lcd_write_yuv420_lines