diff options
author | Thomas Martitz <kugel@rockbox.org> | 2012-01-07 23:22:28 +0100 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2012-01-22 18:46:45 +0100 |
commit | 094cbd586ffd16c75e11dd7eb32dbe7f79c21a99 (patch) | |
tree | aee62d8651c75c83daf81238a18c35f508d2f887 /firmware/asm | |
parent | a035261089403de259e74ce4dd196e2715138ed2 (diff) | |
download | rockbox-094cbd586ffd16c75e11dd7eb32dbe7f79c21a99.tar.gz rockbox-094cbd586ffd16c75e11dd7eb32dbe7f79c21a99.zip |
Implement a C version lcd-as-memframe.c and move it and the asm to firmware/asm.
Change-Id: I20c3af0368202493d54fb776530300a39d47873a
Diffstat (limited to 'firmware/asm')
-rw-r--r-- | firmware/asm/SOURCES | 7 | ||||
-rw-r--r-- | firmware/asm/arm/lcd-as-memframe.S | 692 | ||||
-rw-r--r-- | firmware/asm/lcd-as-memframe.c | 181 |
3 files changed, 880 insertions, 0 deletions
diff --git a/firmware/asm/SOURCES b/firmware/asm/SOURCES index 805727ea93..216089f003 100644 --- a/firmware/asm/SOURCES +++ b/firmware/asm/SOURCES | |||
@@ -5,3 +5,10 @@ memmove.c | |||
5 | memset.c | 5 | memset.c |
6 | strlen.c | 6 | strlen.c |
7 | #endif | 7 | #endif |
8 | |||
9 | #if (defined(SANSA_E200) || defined(GIGABEAT_F) || defined(GIGABEAT_S) || \ | ||
10 | defined(CREATIVE_ZVx) || defined(SANSA_CONNECT) || defined(SANSA_FUZEPLUS) || \ | ||
11 | defined(COWON_D2) || defined(MINI2440) || (defined(MROBE_500) && !defined(LCD_USE_DMA))) && \ | ||
12 | !defined(SIMULATOR) | ||
13 | lcd-as-memframe.c | ||
14 | #endif | ||
diff --git a/firmware/asm/arm/lcd-as-memframe.S b/firmware/asm/arm/lcd-as-memframe.S new file mode 100644 index 0000000000..52ab0447c2 --- /dev/null +++ b/firmware/asm/arm/lcd-as-memframe.S | |||
@@ -0,0 +1,692 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Michael Sevakis | ||
11 | * | ||
12 | * ARM code for memory framebuffer LCDs | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "cpu.h" | ||
26 | |||
27 | /**************************************************************************** | ||
28 | * void lcd_copy_buffer_rect(fb_data *dst, fb_data *src, int width, | ||
29 | * int height); | ||
30 | */ | ||
31 | .section .icode.lcd_copy_buffer_rect, "ax", %progbits | ||
32 | .align 2 | ||
33 | .global lcd_copy_buffer_rect | ||
34 | .type lcd_copy_buffer_rect, %function | ||
35 | @ r0 = dst | ||
36 | @ r1 = src | ||
37 | @ r2 = width | ||
38 | @ r3 = height | ||
39 | lcd_copy_buffer_rect: @ | ||
40 | stmfd sp!, { r4-r11, lr } @ save non-scratch regs | ||
41 | mov r5, r2 @ r5 = cached width | ||
42 | rsb r4, r2, #LCD_WIDTH @ r4 = LCD_WIDTH - width | ||
43 | 10: @ copy line @ | ||
44 | subs r2, r5, #1 @ r2 = width - 1 | ||
45 | beq 40f @ finish line @ one halfword? skip to trailing copy | ||
46 | tst r0, #2 @ word aligned? | ||
47 | beq 20f @ rem copy @ yes? skip to word copy | ||
48 | ldrh r6, [r1], #2 @ copy leading halfword | ||
49 | subs r2, r2, #1 @ | ||
50 | strh r6, [r0], #2 @ | ||
51 | ble 40f @ finish line @ next line if lt or finish | ||
52 | @ trailing halfword if eq | ||
53 | 20: @ rem copy @ | ||
54 | sub r14, r2, #1 @ wrap remaining width mod 16 after word | ||
55 | @ align (rw) | ||
56 | and r14, r14, #0xe @ r14 = 14, 0, 2, 4, 6, 8, 10, 12 | ||
57 | add pc, pc, r14, lsl #3 @ branch to 32-byte align | ||
58 | nop @ | ||
59 | ldr r6, [r1], #4 @ rw % 16 = 2 or 3 (0) | ||
60 | subs r2, r2, #2 @ | ||
61 | str r6, [r0], #4 @ | ||
62 | b 25f @ copy up done @ | ||
63 | ldmia r1!, { r6-r7 } @ rw % 16 = 4 or 5 (2) | ||
64 | subs r2, r2, #4 @ | ||
65 | stmia r0!, { r6-r7 } @ | ||
66 | b 25f @ copy up done @ | ||
67 | ldmia r1!, { r6-r8 } @ rw % 16 = 6 or 7 (4) | ||
68 | subs r2, r2, #6 @ | ||
69 | stmia r0!, { r6-r8 } @ | ||
70 | b 25f @ copy up done @ | ||
71 | ldmia r1!, { r6-r9 } @ rw % 16 = 8 or 9 (6) | ||
72 | subs r2, r2, #8 @ | ||
73 | stmia r0!, { r6-r9 } @ | ||
74 | b 25f @ copy up done @ | ||
75 | ldmia r1!, { r6-r10 } @ rw % 16 = 10 or 11 (8) | ||
76 | subs r2, r2, #10 @ | ||
77 | stmia r0!, { r6-r10 } @ | ||
78 | b 25f @ copy up done @ | ||
79 | ldmia r1!, { r6-r11 } @ rw % 16 = 12 or 13 (10) | ||
80 | subs r2, r2, #12 @ | ||
81 | stmia r0!, { r6-r11 } @ | ||
82 | b 25f @ copy up done @ | ||
83 | ldmia r1!, { r6-r12 } @ rw % 16 = 14 or 15 (12) | ||
84 | subs r2, r2, #14 @ | ||
85 | stmia r0!, { r6-r12 } @ | ||
86 | 25: @ copy up done @ | ||
87 | ble 40f @ finish line @ | ||
88 | 30: @ octword loop @ rw % 16 = 0 or 1 (14) | ||
89 | ldmia r1!, { r6-r12, r14 } @ copy 16 pixels per loop | ||
90 | subs r2, r2, #16 @ | ||
91 | stmia r0!, { r6-r12, r14 } @ | ||
92 | bgt 30b @ octword loop @ | ||
93 | 40: @ finish line @ | ||
94 | ldreqh r6, [r1], #2 @ finish last halfword if eq ... | ||
95 | add r1, r1, r4, lsl #1 @ | ||
96 | streqh r6, [r0], #2 @ ... | ||
97 | add r0, r0, r4, lsl #1 @ | ||
98 | subs r3, r3, #1 @ next line | ||
99 | bgt 10b @ copy line @ | ||
100 | ldmpc regs=r4-r11 @ restore regs and return | ||
101 | .size lcd_copy_buffer_rect, .-lcd_copy_buffer_rect | ||
102 | |||
103 | |||
104 | /**************************************************************************** | ||
105 | * void lcd_write_yuv420_lines(fb_data *dst, | ||
106 | * unsigned char const * const src[3], | ||
107 | * int width, | ||
108 | * int stride); | ||
109 | * | ||
110 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
111 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
112 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
113 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
114 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
115 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
116 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
117 | * | ||
118 | * Write four RGB565 pixels in the following order on each loop: | ||
119 | * 1 3 + > down | ||
120 | * 2 4 \/ left | ||
121 | */ | ||
122 | .section .icode.lcd_write_yuv420_lines, "ax", %progbits | ||
123 | .align 2 | ||
124 | .global lcd_write_yuv420_lines | ||
125 | .type lcd_write_yuv420_lines, %function | ||
126 | lcd_write_yuv420_lines: | ||
127 | @ r0 = dst | ||
128 | @ r1 = yuv_src | ||
129 | @ r2 = width | ||
130 | @ r3 = stride | ||
131 | stmfd sp!, { r4-r10, lr } @ save non-scratch | ||
132 | ldmia r1, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
133 | @ r5 = yuv_src[1] = Cb_p | ||
134 | @ r6 = yuv_src[2] = Cr_p | ||
135 | @ r1 = scratch | ||
136 | sub r3, r3, #1 @ | ||
137 | 10: @ loop line @ | ||
138 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
139 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
140 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
141 | @ | ||
142 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
143 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
144 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
145 | @ | ||
146 | sub r8, r8, #128 @ Cb -= 128 | ||
147 | sub r9, r9, #128 @ Cr -= 128 | ||
148 | @ | ||
149 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
150 | add r10, r10, r10, asl #4 @ | ||
151 | add r10, r10, r8, asl #3 @ | ||
152 | add r10, r10, r8, asl #4 @ | ||
153 | @ | ||
154 | add lr, r9, r9, asl #2 @ r9 = Cr*101 | ||
155 | add lr, lr, r9, asl #5 @ | ||
156 | add r9, lr, r9, asl #6 @ | ||
157 | @ | ||
158 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
159 | mov r8, r8, asr #2 @ | ||
160 | add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9 | ||
161 | mov r9, r9, asr #9 @ | ||
162 | rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8 | ||
163 | mov r10, r10, asr #8 @ | ||
164 | @ compute R, G, and B | ||
165 | add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu | ||
166 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
167 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
168 | @ | ||
169 | #if ARM_ARCH >= 6 | ||
170 | usat r1, #5, r1 @ clamp b | ||
171 | usat lr, #5, lr @ clamp r | ||
172 | usat r7, #6, r7 @ clamp g | ||
173 | #else | ||
174 | orr r12, r1, lr @ check if clamping is needed... | ||
175 | orr r12, r12, r7, asr #1 @ ...at all | ||
176 | cmp r12, #31 @ | ||
177 | bls 15f @ no clamp @ | ||
178 | cmp r1, #31 @ clamp b | ||
179 | mvnhi r1, r1, asr #31 @ | ||
180 | andhi r1, r1, #31 @ | ||
181 | cmp lr, #31 @ clamp r | ||
182 | mvnhi lr, lr, asr #31 @ | ||
183 | andhi lr, lr, #31 @ | ||
184 | cmp r7, #63 @ clamp g | ||
185 | mvnhi r7, r7, asr #31 @ | ||
186 | andhi r7, r7, #63 @ | ||
187 | 15: @ no clamp @ | ||
188 | #endif | ||
189 | @ | ||
190 | ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride) | ||
191 | @ | ||
192 | orr r1, r1, r7, lsl #5 @ r4 |= (g << 5) | ||
193 | orr r1, r1, lr, lsl #11 @ r4 = b | (r << 11) | ||
194 | |||
195 | #if LCD_WIDTH >= LCD_HEIGHT | ||
196 | strh r1, [r0] @ | ||
197 | #elif LCD_WIDTH < 256 | ||
198 | strh r1, [r0], #LCD_WIDTH @ store pixel | ||
199 | #else | ||
200 | strh r1, [r0] @ | ||
201 | #endif | ||
202 | @ | ||
203 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
204 | add r12, r7, r7, asl #2 @ | ||
205 | add r7, r12, r7, asl #5 @ | ||
206 | @ compute R, G, and B | ||
207 | add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu | ||
208 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
209 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
210 | @ | ||
211 | #if ARM_ARCH >= 6 | ||
212 | usat r1, #5, r1 @ clamp b | ||
213 | usat lr, #5, lr @ clamp r | ||
214 | usat r7, #6, r7 @ clamp g | ||
215 | #else | ||
216 | orr r12, r1, lr @ check if clamping is needed... | ||
217 | orr r12, r12, r7, asr #1 @ ...at all | ||
218 | cmp r12, #31 @ | ||
219 | bls 15f @ no clamp @ | ||
220 | cmp r1, #31 @ clamp b | ||
221 | mvnhi r1, r1, asr #31 @ | ||
222 | andhi r1, r1, #31 @ | ||
223 | cmp lr, #31 @ clamp r | ||
224 | mvnhi lr, lr, asr #31 @ | ||
225 | andhi lr, lr, #31 @ | ||
226 | cmp r7, #63 @ clamp g | ||
227 | mvnhi r7, r7, asr #31 @ | ||
228 | andhi r7, r7, #63 @ | ||
229 | 15: @ no clamp @ | ||
230 | #endif | ||
231 | @ | ||
232 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
233 | @ | ||
234 | orr r1, r1, lr, lsl #11 @ r1 = b | (r << 11) | ||
235 | orr r1, r1, r7, lsl #5 @ r1 |= (g << 5) | ||
236 | |||
237 | #if LCD_WIDTH >= LCD_HEIGHT | ||
238 | add r0, r0, #2*LCD_WIDTH @ | ||
239 | strh r1, [r0] @ store pixel | ||
240 | sub r0, r0, #2*LCD_WIDTH @ | ||
241 | #elif LCD_WIDTH < 256 | ||
242 | strh r1, [r0, #-LCD_WIDTH-2] @ store pixel | ||
243 | #else | ||
244 | strh r1, [r0, #-2] @ | ||
245 | add r0, r0, #LCD_WIDTH @ | ||
246 | #endif | ||
247 | @ | ||
248 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
249 | add r12, r7, r7, asl #2 @ | ||
250 | add r7, r12, r7, asl #5 @ | ||
251 | @ compute R, G, and B | ||
252 | add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu | ||
253 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
254 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
255 | @ | ||
256 | #if ARM_ARCH >= 6 | ||
257 | usat r1, #5, r1 @ clamp b | ||
258 | usat lr, #5, lr @ clamp r | ||
259 | usat r7, #6, r7 @ clamp g | ||
260 | #else | ||
261 | orr r12, r1, lr @ check if clamping is needed... | ||
262 | orr r12, r12, r7, asr #1 @ ...at all | ||
263 | cmp r12, #31 @ | ||
264 | bls 15f @ no clamp @ | ||
265 | cmp r1, #31 @ clamp b | ||
266 | mvnhi r1, r1, asr #31 @ | ||
267 | andhi r1, r1, #31 @ | ||
268 | cmp lr, #31 @ clamp r | ||
269 | mvnhi lr, lr, asr #31 @ | ||
270 | andhi lr, lr, #31 @ | ||
271 | cmp r7, #63 @ clamp g | ||
272 | mvnhi r7, r7, asr #31 @ | ||
273 | andhi r7, r7, #63 @ | ||
274 | 15: @ no clamp @ | ||
275 | #endif | ||
276 | @ | ||
277 | ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride) | ||
278 | @ | ||
279 | orr r1, r1, r7, lsl #5 @ r1 = b | (g << 5) | ||
280 | orr r1, r1, lr, lsl #11 @ r1 |= (r << 11) | ||
281 | |||
282 | #if LCD_WIDTH >= LCD_HEIGHT | ||
283 | strh r1, [r0, #2] | ||
284 | #elif LCD_WIDTH < 256 | ||
285 | strh r1, [r0, #LCD_WIDTH]! @ store pixel | ||
286 | #else | ||
287 | strh r1, [r0] @ | ||
288 | #endif | ||
289 | @ | ||
290 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
291 | add r12, r7, r7, asl #2 @ | ||
292 | add r7, r12, r7, asl #5 @ | ||
293 | @ compute R, G, and B | ||
294 | add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu | ||
295 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
296 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
297 | @ | ||
298 | #if ARM_ARCH >= 6 | ||
299 | usat r1, #5, r1 @ clamp b | ||
300 | usat lr, #5, lr @ clamp r | ||
301 | usat r7, #6, r7 @ clamp g | ||
302 | #else | ||
303 | orr r12, r1, lr @ check if clamping is needed... | ||
304 | orr r12, r12, r7, asr #1 @ ...at all | ||
305 | cmp r12, #31 @ | ||
306 | bls 15f @ no clamp @ | ||
307 | cmp r1, #31 @ clamp b | ||
308 | mvnhi r1, r1, asr #31 @ | ||
309 | andhi r1, r1, #31 @ | ||
310 | cmp lr, #31 @ clamp r | ||
311 | mvnhi lr, lr, asr #31 @ | ||
312 | andhi lr, lr, #31 @ | ||
313 | cmp r7, #63 @ clamp g | ||
314 | mvnhi r7, r7, asr #31 @ | ||
315 | andhi r7, r7, #63 @ | ||
316 | 15: @ no clamp @ | ||
317 | #endif | ||
318 | @ | ||
319 | orr r12, r1, lr, lsl #11 @ r12 = b | (r << 11) | ||
320 | orr r12, r12, r7, lsl #5 @ r12 |= (g << 5) | ||
321 | |||
322 | #if LCD_WIDTH >= LCD_HEIGHT | ||
323 | add r0, r0, #2*LCD_WIDTH | ||
324 | strh r12, [r0, #2] | ||
325 | #if LCD_WIDTH <= 512 | ||
326 | sub r0, r0, #(2*LCD_WIDTH)-4 | ||
327 | #else | ||
328 | sub r0, r0, #(2*LCD_WIDTH) | ||
329 | add r0, r0, #4 | ||
330 | #endif | ||
331 | #else | ||
332 | strh r12, [r0, #-2] @ store pixel | ||
333 | #if LCD_WIDTH < 256 | ||
334 | add r0, r0, #2*LCD_WIDTH @ | ||
335 | #else | ||
336 | add r0, r0, #LCD_WIDTH @ | ||
337 | #endif | ||
338 | #endif | ||
339 | @ | ||
340 | subs r2, r2, #2 @ subtract block from width | ||
341 | bgt 10b @ loop line @ | ||
342 | @ | ||
343 | ldmpc regs=r4-r10 @ restore registers and return | ||
344 | .ltorg @ dump constant pool | ||
345 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
346 | |||
347 | |||
348 | /**************************************************************************** | ||
349 | * void lcd_write_yuv420_lines_odither(fb_data *dst, | ||
350 | * unsigned char const * const src[3], | ||
351 | * int width, | ||
352 | * int stride, | ||
353 | * int x_screen, | ||
354 | * int y_screen); | ||
355 | * | ||
356 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
357 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
358 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
359 | * Red scaled at twice g & b but at same precision to place it in correct | ||
360 | * bit position after multiply and leave instruction count lower. | ||
361 | * |R| |258 0 408| |Y' - 16| | ||
362 | * |G| = |149 -49 -104| |Cb - 128| | ||
363 | * |B| |149 258 0| |Cr - 128| | ||
364 | * | ||
365 | * Write four RGB565 pixels in the following order on each loop: | ||
366 | * 1 3 + > down | ||
367 | * 2 4 \/ left | ||
368 | * | ||
369 | * Kernel pattern (raw|rotated|use order): | ||
370 | * 5 3 4 2 2 6 3 7 row0 row2 > down | ||
371 | * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left | ||
372 | * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/ | ||
373 | * 0 6 1 7 5 1 4 0 | ||
374 | */ | ||
375 | .section .icode.lcd_write_yuv420_lines_odither, "ax", %progbits | ||
376 | .align 2 | ||
377 | .global lcd_write_yuv420_lines_odither | ||
378 | .type lcd_write_yuv420_lines_odither, %function | ||
379 | lcd_write_yuv420_lines_odither: | ||
380 | @ r0 = dst | ||
381 | @ r1 = yuv_src | ||
382 | @ r2 = width | ||
383 | @ r3 = stride | ||
384 | @ [sp] = x_screen | ||
385 | @ [sp+4] = y_screen | ||
386 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
387 | ldmia r1, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
388 | @ r5 = yuv_src[1] = Cb_p | ||
389 | @ r6 = yuv_src[2] = Cr_p | ||
390 | @ | ||
391 | sub r3, r3, #1 @ | ||
392 | add r1, sp, #36 @ Line up pattern and kernel quadrant | ||
393 | ldmia r1, { r12, r14 } @ | ||
394 | eor r14, r14, r12 @ | ||
395 | and r14, r14, #0x2 @ | ||
396 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
397 | 10: @ loop line @ | ||
398 | @ | ||
399 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
400 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
401 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
402 | @ | ||
403 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
404 | @ | ||
405 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
406 | add r12, r7, r7, asl #2 @ | ||
407 | add r12, r12, r12, asl #4 @ | ||
408 | add r7, r12, r7, asl #6 @ | ||
409 | @ | ||
410 | sub r8, r8, #128 @ Cb -= 128 | ||
411 | sub r9, r9, #128 @ Cr -= 128 | ||
412 | @ | ||
413 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
414 | add r10, r10, r8, asl #5 @ | ||
415 | add r10, r10, r9, asl #3 @ | ||
416 | add r10, r10, r9, asl #5 @ | ||
417 | add r10, r10, r9, asl #6 @ | ||
418 | @ | ||
419 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
420 | add r8, r8, r8, asl #7 @ | ||
421 | @ | ||
422 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
423 | add r9, r9, r9, asl #4 @ | ||
424 | mov r9, r9, asl #3 @ | ||
425 | @ | ||
426 | @ compute R, G, and B | ||
427 | add r1, r8, r7 @ r1 = b' = Y + bu | ||
428 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
429 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
430 | @ | ||
431 | @ r8 = bu, r9 = rv, r10 = guv | ||
432 | @ | ||
433 | sub r12, r1, r1, lsr #5 @ r1 = 31/32*b + b/256 | ||
434 | add r1, r12, r1, lsr #8 @ | ||
435 | @ | ||
436 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
437 | add r11, r12, r11, lsr #8 @ | ||
438 | @ | ||
439 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
440 | add r7, r12, r7, lsr #8 @ | ||
441 | @ | ||
442 | add r12, r14, #0x100 @ | ||
443 | @ | ||
444 | add r1, r1, r12 @ b = r1 + delta | ||
445 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
446 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
447 | @ | ||
448 | #if ARM_ARCH >= 6 | ||
449 | usat r11, #5, r11, asr #11 @ clamp r | ||
450 | usat r7, #6, r7, asr #9 @ clamp g | ||
451 | usat r1, #5, r1, asr #10 @ clamp b | ||
452 | @ | ||
453 | ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride) | ||
454 | @ | ||
455 | orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11) | ||
456 | orr r1, r1, r7, lsl #5 @ r1 |= (g << 5) | ||
457 | #else | ||
458 | orr r12, r1, r11, asr #1 @ check if clamping is needed... | ||
459 | orr r12, r12, r7 @ ...at all | ||
460 | movs r12, r12, asr #15 @ | ||
461 | beq 15f @ no clamp @ | ||
462 | movs r12, r1, asr #15 @ clamp b | ||
463 | mvnne r1, r12, lsr #15 @ | ||
464 | andne r1, r1, #0x7c00 @ mask b only if clamped | ||
465 | movs r12, r11, asr #16 @ clamp r | ||
466 | mvnne r11, r12, lsr #16 @ | ||
467 | movs r12, r7, asr #15 @ clamp g | ||
468 | mvnne r7, r12, lsr #15 @ | ||
469 | 15: @ no clamp @ | ||
470 | @ | ||
471 | ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride) | ||
472 | @ | ||
473 | and r11, r11, #0xf800 @ pack pixel | ||
474 | and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) | | ||
475 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
476 | orr r1, r11, r1, lsr #10 @ (b >> 10) | ||
477 | #endif | ||
478 | @ | ||
479 | #if LCD_WIDTH >= LCD_HEIGHT | ||
480 | strh r1, [r0] @ | ||
481 | #elif LCD_WIDTH < 256 | ||
482 | strh r1, [r0], #LCD_WIDTH @ store pixel | ||
483 | #else | ||
484 | strh r1, [r0] @ | ||
485 | #endif | ||
486 | @ | ||
487 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
488 | add r12, r7, r7, asl #2 @ | ||
489 | add r12, r12, r12, asl #4 @ | ||
490 | add r7, r12, r7, asl #6 @ | ||
491 | @ compute R, G, and B | ||
492 | add r1, r8, r7 @ r1 = b' = Y + bu | ||
493 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
494 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
495 | @ | ||
496 | sub r12, r1, r1, lsr #5 @ r1 = 31/32*b' + b'/256 | ||
497 | add r1, r12, r1, lsr #8 @ | ||
498 | @ | ||
499 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
500 | add r11, r12, r11, lsr #8 @ | ||
501 | @ | ||
502 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
503 | add r7, r12, r7, lsr #8 @ | ||
504 | @ | ||
505 | add r12, r14, #0x200 @ | ||
506 | @ | ||
507 | add r1, r1, r12 @ b = r1 + delta | ||
508 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
509 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
510 | @ | ||
511 | #if ARM_ARCH >= 6 | ||
512 | usat r11, #5, r11, asr #11 @ clamp r | ||
513 | usat r7, #6, r7, asr #9 @ clamp g | ||
514 | usat r1, #5, r1, asr #10 @ clamp b | ||
515 | @ | ||
516 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
517 | @ | ||
518 | orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11) | ||
519 | orr r1, r1, r7, lsl #5 @ r1 |= (g << 5) | ||
520 | #else | ||
521 | orr r12, r1, r11, asr #1 @ check if clamping is needed... | ||
522 | orr r12, r12, r7 @ ...at all | ||
523 | movs r12, r12, asr #15 @ | ||
524 | beq 15f @ no clamp @ | ||
525 | movs r12, r1, asr #15 @ clamp b | ||
526 | mvnne r1, r12, lsr #15 @ | ||
527 | andne r1, r1, #0x7c00 @ mask b only if clamped | ||
528 | movs r12, r11, asr #16 @ clamp r | ||
529 | mvnne r11, r12, lsr #16 @ | ||
530 | movs r12, r7, asr #15 @ clamp g | ||
531 | mvnne r7, r12, lsr #15 @ | ||
532 | 15: @ no clamp @ | ||
533 | @ | ||
534 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
535 | @ | ||
536 | and r11, r11, #0xf800 @ pack pixel | ||
537 | and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) | | ||
538 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
539 | orr r1, r11, r1, lsr #10 @ (b >> 10) | ||
540 | #endif | ||
541 | @ | ||
542 | #if LCD_WIDTH >= LCD_HEIGHT | ||
543 | add r0, r0, #2*LCD_WIDTH @ | ||
544 | strh r1, [r0] @ store pixel | ||
545 | sub r0, r0, #2*LCD_WIDTH @ | ||
546 | #elif LCD_WIDTH < 256 | ||
547 | strh r1, [r0, #-LCD_WIDTH-2] @ store pixel | ||
548 | #else | ||
549 | strh r1, [r0, #-2] @ store pixel | ||
550 | add r0, r0, #LCD_WIDTH @ | ||
551 | #endif | ||
552 | @ | ||
553 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
554 | add r12, r7, r7, asl #2 @ | ||
555 | add r12, r12, r12, asl #4 @ | ||
556 | add r7, r12, r7, asl #6 @ | ||
557 | @ compute R, G, and B | ||
558 | add r1, r8, r7 @ r1 = b' = Y + bu | ||
559 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
560 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
561 | @ | ||
562 | @ r8 = bu, r9 = rv, r10 = guv | ||
563 | @ | ||
564 | sub r12, r1, r1, lsr #5 @ r1 = 31/32*b' + b'/256 | ||
565 | add r1, r12, r1, lsr #8 @ | ||
566 | @ | ||
567 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
568 | add r11, r12, r11, lsr #8 @ | ||
569 | @ | ||
570 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
571 | add r7, r12, r7, lsr #8 @ | ||
572 | @ | ||
573 | add r12, r14, #0x300 @ | ||
574 | @ | ||
575 | add r1, r1, r12 @ b = r1 + delta | ||
576 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
577 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
578 | @ | ||
579 | #if ARM_ARCH >= 6 | ||
580 | usat r11, #5, r11, asr #11 @ clamp r | ||
581 | usat r7, #6, r7, asr #9 @ clamp g | ||
582 | usat r1, #5, r1, asr #10 @ clamp b | ||
583 | @ | ||
584 | ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride) | ||
585 | @ | ||
586 | orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11) | ||
587 | orr r1, r1, r7, lsl #5 @ r1 |= (g << 5) | ||
588 | #else | ||
589 | orr r12, r1, r11, asr #1 @ check if clamping is needed... | ||
590 | orr r12, r12, r7 @ ...at all | ||
591 | movs r12, r12, asr #15 @ | ||
592 | beq 15f @ no clamp @ | ||
593 | movs r12, r1, asr #15 @ clamp b | ||
594 | mvnne r1, r12, lsr #15 @ | ||
595 | andne r1, r1, #0x7c00 @ mask b only if clamped | ||
596 | movs r12, r11, asr #16 @ clamp r | ||
597 | mvnne r11, r12, lsr #16 @ | ||
598 | movs r12, r7, asr #15 @ clamp g | ||
599 | mvnne r7, r12, lsr #15 @ | ||
600 | 15: @ no clamp @ | ||
601 | @ | ||
602 | ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride) | ||
603 | @ | ||
604 | and r11, r11, #0xf800 @ pack pixel | ||
605 | and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) | | ||
606 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
607 | orr r1, r11, r1, lsr #10 @ (b >> 10) | ||
608 | #endif | ||
609 | @ | ||
610 | #if LCD_WIDTH >= LCD_HEIGHT | ||
611 | strh r1, [r0, #2] | ||
612 | #elif LCD_WIDTH < 256 | ||
613 | strh r1, [r0, #LCD_WIDTH]! @ store pixel | ||
614 | #else | ||
615 | strh r1, [r0] @ | ||
616 | #endif | ||
617 | |||
618 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
619 | add r12, r7, r7, asl #2 @ | ||
620 | add r12, r12, r12, asl #4 @ | ||
621 | add r7, r12, r7, asl #6 @ | ||
622 | @ compute R, G, and B | ||
623 | add r1, r8, r7 @ r1 = b' = Y + bu | ||
624 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
625 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
626 | @ | ||
627 | sub r12, r1, r1, lsr #5 @ r1 = 31/32*b + b/256 | ||
628 | add r1, r12, r1, lsr #8 @ | ||
629 | @ | ||
630 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
631 | add r11, r12, r11, lsr #8 @ | ||
632 | @ | ||
633 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
634 | add r7, r12, r7, lsr #8 @ | ||
635 | @ | ||
636 | @ This element is zero - use r14 @ | ||
637 | @ | ||
638 | add r1, r1, r14 @ b = r1 + delta | ||
639 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
640 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
641 | @ | ||
642 | #if ARM_ARCH >= 6 | ||
643 | usat r11, #5, r11, asr #11 @ clamp r | ||
644 | usat r7, #6, r7, asr #9 @ clamp g | ||
645 | usat r1, #5, r1, asr #10 @ clamp b | ||
646 | @ | ||
647 | orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11) | ||
648 | orr r1, r1, r7, lsl #5 @ r1 |= (g << 5) | ||
649 | #else | ||
650 | orr r12, r1, r11, asr #1 @ check if clamping is needed... | ||
651 | orr r12, r12, r7 @ ...at all | ||
652 | movs r12, r12, asr #15 @ | ||
653 | beq 15f @ no clamp @ | ||
654 | movs r12, r1, asr #15 @ clamp b | ||
655 | mvnne r1, r12, lsr #15 @ | ||
656 | andne r1, r1, #0x7c00 @ mask b only if clamped | ||
657 | movs r12, r11, asr #16 @ clamp r | ||
658 | mvnne r11, r12, lsr #16 @ | ||
659 | movs r12, r7, asr #15 @ clamp g | ||
660 | mvnne r7, r12, lsr #15 @ | ||
661 | 15: @ no clamp @ | ||
662 | @ | ||
663 | and r11, r11, #0xf800 @ pack pixel | ||
664 | and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) | | ||
665 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
666 | orr r1, r11, r1, lsr #10 @ (b >> 10) | ||
667 | #endif | ||
668 | @ | ||
669 | #if LCD_WIDTH >= LCD_HEIGHT | ||
670 | add r0, r0, #2*LCD_WIDTH | ||
671 | strh r1, [r0, #2] @ store pixel | ||
672 | #if LCD_WIDTH <= 512 | ||
673 | sub r0, r0, #(2*LCD_WIDTH)-4 | ||
674 | #else | ||
675 | sub r0, r0, #(2*LCD_WIDTH) | ||
676 | add r0, r0, #4 | ||
677 | #endif | ||
678 | #else | ||
679 | strh r1, [r0, #-2] @ store pixel | ||
680 | #if LCD_WIDTH < 256 | ||
681 | add r0, r0, #2*LCD_WIDTH @ | ||
682 | #else | ||
683 | add r0, r0, #LCD_WIDTH @ | ||
684 | #endif | ||
685 | #endif | ||
686 | @ | ||
687 | subs r2, r2, #2 @ subtract block from width | ||
688 | bgt 10b @ loop line @ | ||
689 | @ | ||
690 | ldmpc regs=r4-r11 @ restore registers and return | ||
691 | .ltorg @ dump constant pool | ||
692 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/asm/lcd-as-memframe.c b/firmware/asm/lcd-as-memframe.c new file mode 100644 index 0000000000..5f4917b721 --- /dev/null +++ b/firmware/asm/lcd-as-memframe.c | |||
@@ -0,0 +1,181 @@ | |||
1 | |||
2 | #include <string.h> | ||
3 | #include "lcd.h" | ||
4 | void lcd_copy_buffer_rect(fb_data *dst, fb_data *src, int width, int height) | ||
5 | { | ||
6 | do { | ||
7 | memcpy(dst, src, width * sizeof(fb_data)); | ||
8 | src += LCD_WIDTH; | ||
9 | dst += LCD_WIDTH; | ||
10 | } while (--height); | ||
11 | } | ||
12 | |||
13 | #define YFAC (74) | ||
14 | #define RVFAC (101) | ||
15 | #define GUFAC (-24) | ||
16 | #define GVFAC (-51) | ||
17 | #define BUFAC (128) | ||
18 | |||
19 | static inline int clamp(int val, int min, int max) | ||
20 | { | ||
21 | if (val < min) | ||
22 | val = min; | ||
23 | else if (val > max) | ||
24 | val = max; | ||
25 | return val; | ||
26 | } | ||
27 | |||
28 | extern void lcd_write_yuv420_lines(fb_data *dst, | ||
29 | unsigned char const * const src[3], | ||
30 | int width, | ||
31 | int stride) | ||
32 | { | ||
33 | /* Draw a partial YUV colour bitmap - similiar behavior to lcd_blit_yuv | ||
34 | in the core */ | ||
35 | const unsigned char *ysrc, *usrc, *vsrc; | ||
36 | int height = 2, linecounter; | ||
37 | fb_data *row_end; | ||
38 | |||
39 | /* width and height must be >= 2 and an even number */ | ||
40 | width &= ~1; | ||
41 | linecounter = height >> 1; | ||
42 | |||
43 | #if LCD_WIDTH >= LCD_HEIGHT | ||
44 | row_end = dst + width; | ||
45 | #else | ||
46 | row_end = dst + LCD_WIDTH * width; | ||
47 | #endif | ||
48 | |||
49 | ysrc = src[0]; | ||
50 | usrc = src[1]; | ||
51 | vsrc = src[2]; | ||
52 | |||
53 | /* stride => amount to jump from end of last row to start of next */ | ||
54 | stride -= width; | ||
55 | |||
56 | /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ | ||
57 | |||
58 | do | ||
59 | { | ||
60 | int y, cb, cr, rv, guv, bu, r, g, b; | ||
61 | |||
62 | y = YFAC*(*ysrc++ - 16); | ||
63 | cb = *usrc++ - 128; | ||
64 | cr = *vsrc++ - 128; | ||
65 | |||
66 | rv = RVFAC*cr; | ||
67 | guv = GUFAC*cb + GVFAC*cr; | ||
68 | bu = BUFAC*cb; | ||
69 | |||
70 | r = y + rv; | ||
71 | g = y + guv; | ||
72 | b = y + bu; | ||
73 | |||
74 | if ((unsigned)(r | g | b) > 64*256-1) | ||
75 | { | ||
76 | r = clamp(r, 0, 64*256-1); | ||
77 | g = clamp(g, 0, 64*256-1); | ||
78 | b = clamp(b, 0, 64*256-1); | ||
79 | } | ||
80 | |||
81 | *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); | ||
82 | |||
83 | #if LCD_WIDTH >= LCD_HEIGHT | ||
84 | dst++; | ||
85 | #else | ||
86 | dst += LCD_WIDTH; | ||
87 | #endif | ||
88 | |||
89 | y = YFAC*(*ysrc++ - 16); | ||
90 | r = y + rv; | ||
91 | g = y + guv; | ||
92 | b = y + bu; | ||
93 | |||
94 | if ((unsigned)(r | g | b) > 64*256-1) | ||
95 | { | ||
96 | r = clamp(r, 0, 64*256-1); | ||
97 | g = clamp(g, 0, 64*256-1); | ||
98 | b = clamp(b, 0, 64*256-1); | ||
99 | } | ||
100 | |||
101 | *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); | ||
102 | |||
103 | #if LCD_WIDTH >= LCD_HEIGHT | ||
104 | dst++; | ||
105 | #else | ||
106 | dst += LCD_WIDTH; | ||
107 | #endif | ||
108 | } | ||
109 | while (dst < row_end); | ||
110 | |||
111 | ysrc += stride; | ||
112 | usrc -= width >> 1; | ||
113 | vsrc -= width >> 1; | ||
114 | |||
115 | #if LCD_WIDTH >= LCD_HEIGHT | ||
116 | row_end += LCD_WIDTH; | ||
117 | dst += LCD_WIDTH - width; | ||
118 | #else | ||
119 | row_end -= 1; | ||
120 | dst -= LCD_WIDTH*width + 1; | ||
121 | #endif | ||
122 | |||
123 | do | ||
124 | { | ||
125 | int y, cb, cr, rv, guv, bu, r, g, b; | ||
126 | |||
127 | y = YFAC*(*ysrc++ - 16); | ||
128 | cb = *usrc++ - 128; | ||
129 | cr = *vsrc++ - 128; | ||
130 | |||
131 | rv = RVFAC*cr; | ||
132 | guv = GUFAC*cb + GVFAC*cr; | ||
133 | bu = BUFAC*cb; | ||
134 | |||
135 | r = y + rv; | ||
136 | g = y + guv; | ||
137 | b = y + bu; | ||
138 | |||
139 | if ((unsigned)(r | g | b) > 64*256-1) | ||
140 | { | ||
141 | r = clamp(r, 0, 64*256-1); | ||
142 | g = clamp(g, 0, 64*256-1); | ||
143 | b = clamp(b, 0, 64*256-1); | ||
144 | } | ||
145 | |||
146 | *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); | ||
147 | |||
148 | #if LCD_WIDTH >= LCD_HEIGHT | ||
149 | dst++; | ||
150 | #else | ||
151 | dst += LCD_WIDTH; | ||
152 | #endif | ||
153 | |||
154 | y = YFAC*(*ysrc++ - 16); | ||
155 | r = y + rv; | ||
156 | g = y + guv; | ||
157 | b = y + bu; | ||
158 | |||
159 | if ((unsigned)(r | g | b) > 64*256-1) | ||
160 | { | ||
161 | r = clamp(r, 0, 64*256-1); | ||
162 | g = clamp(g, 0, 64*256-1); | ||
163 | b = clamp(b, 0, 64*256-1); | ||
164 | } | ||
165 | |||
166 | *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); | ||
167 | |||
168 | #if LCD_WIDTH >= LCD_HEIGHT | ||
169 | dst++; | ||
170 | #else | ||
171 | dst += LCD_WIDTH; | ||
172 | #endif | ||
173 | } | ||
174 | while (dst < row_end); | ||
175 | } | ||
176 | |||
177 | void lcd_write_yuv420_lines_odither(fb_data *dst, | ||
178 | unsigned char const * const src[3], | ||
179 | int width, int stride, | ||
180 | int x_screen, int y_screen) | ||
181 | __attribute__((alias("lcd_write_yuv420_lines"))); | ||