bugfix
[picodrive.git] / platform / uiq2 / blit.s
1 @ assembly "optimized" blitter and copy functions\r
2 @ all pointers must be word-aligned\r
3 \r
4 @ (c) Copyright 2006, notaz\r
5 @ All Rights Reserved\r
6 \r
7 \r
8 @ Convert 0000bbb0 ggg0rrr0\r
9 @ to      0000rrr0 ggg0bbb0\r
10 \r
11 @ r2,r3 - scratch, lr = 0x000F000F\r
12 .macro convRGB444 reg\r
13     and     r2,   \reg, lr         @ r2=red\r
14     and     r3,   \reg, lr, lsl #8 @ r3=blue\r
15     and     \reg, \reg, lr, lsl #4 @ green stays in place\r
16     orr     \reg, \reg, r2, lsl #8 @ add red back\r
17     orr     \reg, \reg, r3, lsr #8 @ add blue back\r
18 .endm\r
19 \r
20 .global vidConvCpyRGB444 @ void *to, void *from, int pixels\r
21 \r
22 vidConvCpyRGB444:\r
23     stmfd   sp!, {r4-r11,lr}\r
24 \r
25     mov     r12, r2, lsr #4 @ repeats\r
26     mov     lr, #0xF0000\r
27     orr     lr, lr, #0xF    @ lr == pattern 0x000F000F\r
28 \r
29 \r
30 .loopRGB444:\r
31         subs    r12, r12, #1\r
32 \r
33     @ I first thought storing multiple registers would be faster,\r
34     @ but this doesn't seem to be the case, probably because of\r
35     @ slow video memory we are dealing with\r
36         ldmia   r1!, {r4-r11}\r
37     convRGB444 r4\r
38     str     r4, [r0], #4\r
39     convRGB444 r5\r
40     str     r5, [r0], #4\r
41     convRGB444 r6\r
42     str     r6, [r0], #4\r
43     convRGB444 r7\r
44     str     r7, [r0], #4\r
45     convRGB444 r8\r
46     str     r8, [r0], #4\r
47     convRGB444 r9\r
48     str     r9, [r0], #4\r
49     convRGB444 r10\r
50     str     r10, [r0], #4\r
51     convRGB444 r11\r
52     str     r11, [r0], #4\r
53 \r
54     bgt     .loopRGB444\r
55 \r
56 \r
57     ldmfd   sp!, {r4-r11,lr}\r
58     bx      lr\r
59 \r
60 \r
61 @ Convert 0000bbb0 ggg0rrr0\r
62 @ to      rrr00ggg 000bbb00\r
63 \r
64 @ r2,r3 - scratch, lr = 0x07800780\r
65 .macro convRGB565 reg\r
66     and     r2,   \reg, lr,  lsr #7  @ r2=red\r
67     and     r3,   \reg, lr,  lsl #1  @ r3=blue\r
68     and     \reg, lr,   \reg,lsl #3  @ green stays, but needs shifting\r
69     orr     \reg, \reg, r2,  lsl #12 @ add red back\r
70     orr     \reg, \reg, r3,  lsr #7  @ add blue back\r
71 .endm\r
72 \r
73 .global vidConvCpyRGB565 @ void *to, void *from, int pixels\r
74 \r
75 vidConvCpyRGB565:\r
76     stmfd   sp!, {r4-r11,lr}\r
77 \r
78     mov     r12, r2, lsr #4 @ repeats\r
79     mov     lr, #0x07800000\r
80     orr     lr, lr, #0x780  @ lr == pattern 0x07800780\r
81 \r
82 .loopRGB565:\r
83         subs    r12, r12, #1\r
84 \r
85         ldmia   r1!, {r4-r11}\r
86     convRGB565 r4\r
87     str     r4, [r0], #4\r
88     convRGB565 r5\r
89     str     r5, [r0], #4\r
90     convRGB565 r6\r
91     str     r6, [r0], #4\r
92     convRGB565 r7\r
93     str     r7, [r0], #4\r
94     convRGB565 r8\r
95     str     r8, [r0], #4\r
96     convRGB565 r9\r
97     str     r9, [r0], #4\r
98     convRGB565 r10\r
99     str     r10, [r0], #4\r
100     convRGB565 r11\r
101     str     r11, [r0], #4\r
102 \r
103     bgt     .loopRGB565\r
104 \r
105     ldmfd   sp!, {r4-r11,lr}\r
106     bx      lr\r
107 \r
108 \r
109 @ Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0\r
110 @ to      00000000 rrr00000 ggg00000 bbb00000 ...\r
111 \r
112 @ r2,r3 - scratch, lr = 0x0000F000\r
113 @ rin - src reg, rout - dest reg (can be same for both; rout can be r3)\r
114 .macro convRGB32_l rout rin\r
115     and     r2,    \rin,  lr,   lsr #12 @ r2=red\r
116     and     r3,    \rin,  lr,   lsr #4  @ r3=blue\r
117     orr     r2,    r3,    r2,   lsl #24\r
118     and     \rout, lr,    \rin, lsl #8  @ green stays, but needs shifting\r
119     orr     \rout, \rout, r2,   lsr #4  @ add red+blue back\r
120 .endm\r
121 \r
122 @ r2,r3 - scratch, lr = 0x0000F000\r
123 @ rin - src reg, rout - dest reg (can be same for both; rout can be r3)\r
124 .macro convRGB32_h rout rin\r
125     and     r2,    \rin,  lr,   lsl #4  @ r2=red\r
126     mov     r3,    \rin,        lsr #24 @ r3=blue\r
127     orr     r2,    r3,    r2\r
128     and     \rout, lr,    \rin, lsr #8  @ green\r
129     orr     \rout, \rout, r2,   lsl #4\r
130 .endm\r
131 \r
132 @ slightly faster conversion, saves 1 opcode, writes output\r
133 @ lr =  0x00F000F0, out: r3=lower_pix, r2=higher_pix; trashes rin\r
134 .macro convRGB32_2 rin rethigh=0\r
135     and     r2,  lr, \rin, lsr #4 @ blue\r
136     and     r3,  \rin, lr\r
137     orr     r2,  r2,   r3, lsl #8         @ g0b0g0b0\r
138 \r
139     mov     r3,  r2,  lsl #16             @ g0b00000\r
140     and     \rin,lr,  \rin, ror #12       @ 00r000r0 (reversed)\r
141     orr     r3,  r3,  \rin, lsr #16       @ g0b000r0\r
142     mov     r3,  r3,  ror #16             @ r3=low\r
143 \r
144     str     r3, [r0], #4\r
145 \r
146     mov     r2,  r2,  lsr #16\r
147 .if \rethigh\r
148     orr     \rin,r2,  \rin, lsl #16\r
149 .else\r
150     orr     r2,  r2,  \rin, lsl #16\r
151     str     r2, [r0], #4\r
152 .endif\r
153 .endm\r
154 \r
155 \r
156 .global vidConvCpyRGB32 @ void *to, void *from, int pixels\r
157 \r
158 vidConvCpyRGB32:\r
159     stmfd   sp!, {r4-r7,lr}\r
160 \r
161     mov     r12, r2, lsr #3 @ repeats\r
162     mov     lr, #0x00F00000\r
163     orr     lr, lr, #0x00F0\r
164 \r
165 .loopRGB32:\r
166         subs    r12, r12, #1\r
167 \r
168         ldmia   r1!, {r4-r7}\r
169     convRGB32_2 r4\r
170     convRGB32_2 r5\r
171     convRGB32_2 r6\r
172     convRGB32_2 r7\r
173 \r
174     bgt     .loopRGB32\r
175 \r
176     ldmfd   sp!, {r4-r7,lr}\r
177     bx      lr\r
178 \r
179 \r
180 @ -------- M2 stuff ---------\r
181 \r
182 .bss\r
183 tmpstore1d: .long\r
184 \r
185 .text\r
186 tmpstore1:  .long tmpstore1d\r
187 \r
188 \r
189 @ r3 - scratch, ru - reg with 2 pixels from upper col, rl - ... lower col\r
190 .macro rot_str16_90 ru rl\r
191     mov     r3, \rl,lsl #16\r
192     mov     r3, r3, lsr #16\r
193     orr     r3, r3, \ru, lsl #16\r
194     str     r3, [r0], #208*2\r
195     mov     r3, \ru,lsr #16\r
196     mov     r3, r3, lsl #16\r
197     orr     r3, r3, \rl, lsr #16\r
198     str     r3, [r0], #208*2\r
199 .endm\r
200 \r
201 \r
202 .global vidConvCpyM2_16_90 @ void *to, void *from, int width\r
203 \r
204 vidConvCpyM2_16_90:\r
205     stmfd   sp!, {r4-r11,lr}\r
206 \r
207     ldr     r4, =tmpstore1\r
208     str     sp, [r4]               @ save sp, we will need sp reg..\r
209     mov     sp, r0                 @ .. to store our dst\r
210 \r
211     @ crashing beyond this point will be fatal (phone reboots), as Symbian OS expects sp to always point to stack\r
212 \r
213     sub     r2,  r2, #1\r
214     mov     r12, #0x00670000\r
215     orr     r12, r12, r2, lsl #24\r
216     orr     r12, r12, r2           @ r12 == ((208-2)/2 << 16) | ((width-1)<<24) | (width-1)\r
217 \r
218     add     r0,  r0, #206*2\r
219     add     r1,  r1, #8*2          @ skip left border\r
220     add     lr,  r1, #328*2\r
221 \r
222 .loopM2_16_90:\r
223         subs    r12, r12, #1<<24\r
224 \r
225         ldmia   r1!, {r4-r7}\r
226         ldmia   lr!, {r8-r11}\r
227     rot_str16_90 r4 r8\r
228     rot_str16_90 r5 r9\r
229     rot_str16_90 r6 r10\r
230     rot_str16_90 r7 r11\r
231 \r
232     bpl     .loopM2_16_90\r
233 \r
234     add     r12, r12, #1<<24\r
235     subs    r12, r12, #0x00010000\r
236     bmi     .loopM2_16_90_end\r
237 \r
238     add     r0,  sp,  r12, lsr #14 @ calculate new dst pointer\r
239     orr     r12, r12, r12, lsl #24 @ restore the width counter\r
240 \r
241     @ skip remaining pixels on these 2 lines\r
242     mov     r4, #328/8-1         @ width of mode2 in line_pixels/8\r
243     sub     r4, r4, r12, lsr #24\r
244     add     r1, lr, r4,  lsl #4  @ skip src pixels\r
245     add     lr, r1, #328*2\r
246     b       .loopM2_16_90\r
247 \r
248 .loopM2_16_90_end:\r
249     @ restore sp\r
250     ldr     r4, =tmpstore1\r
251     ldr     sp, [r4]\r
252 \r
253     ldmfd   sp!, {r4-r11,lr}\r
254     bx      lr\r
255 \r
256 \r
257 \r
258 @ r3 - scratch, ru - reg with 2 pixels from upper col, rl - ... lower col (for right-to-left copies)\r
259 .macro rot_str16_270 ru rl\r
260     mov     r3, \rl,lsr #16\r
261     mov     r3, r3, lsl #16\r
262     orr     r3, r3, \ru, lsr #16\r
263     str     r3, [r0], #208*2\r
264     mov     r3, \ru,lsl #16\r
265     mov     r3, r3, lsr #16\r
266     orr     r3, r3, \rl, lsl #16\r
267     str     r3, [r0], #208*2\r
268 .endm\r
269 \r
270 \r
271 .global vidConvCpyM2_16_270 @ void *to, void *from, int width\r
272 \r
273 vidConvCpyM2_16_270:\r
274     stmfd   sp!, {r4-r11,lr}\r
275 \r
276     ldr     r4, =tmpstore1\r
277     str     sp, [r4]               @ save sp, we will need sp reg to store our dst\r
278 \r
279     sub     r2,  r2, #1\r
280     mov     r12, #0x00670000\r
281     orr     r12, r12, r2, lsl #24\r
282     orr     r12, r12, r2           @ r12 == ((208-2)/2 << 16) | ((width-1)<<24) | (width-1)\r
283 \r
284     add     r1,  r1, #328*2        @ skip left border+1line\r
285     add     lr,  r1, #328*2\r
286     add     sp,  r0, #206*2        @ adjust for algo\r
287 \r
288 .loopM2_16_270:\r
289         subs    r12, r12, #1<<24\r
290 \r
291         ldmdb   r1!, {r4-r7}\r
292         ldmdb   lr!, {r8-r11}\r
293     rot_str16_270 r7 r11           @ update the screen in incrementing direction, reduces tearing slightly\r
294     rot_str16_270 r6 r10\r
295     rot_str16_270 r5 r9\r
296     rot_str16_270 r4 r8\r
297 \r
298     bpl     .loopM2_16_270\r
299 \r
300     add     r12, r12, #1<<24\r
301     subs    r12, r12, #0x00010000\r
302     bmi     .loopM2_16_90_end      @ same end as in 90\r
303 \r
304     sub     r0,  sp,  r12, lsr #14 @ calculate new dst pointer\r
305     orr     r12, r12, r12, lsl #24 @ restore the width counter\r
306 \r
307     @ skip remaining pixels on these 2 lines\r
308     mov     r4, #328/8-1         @ width of mode2 in line_pixels/8\r
309     sub     r4, r4, r12, lsr #24\r
310     sub     r1, lr, r4,  lsl #4  @ skip src pixels\r
311     add     r1, r1, #328*2*2\r
312     add     lr, r1, #328*2\r
313     b       .loopM2_16_270\r
314 \r
315 \r
316 \r
317 .global vidConvCpyM2_RGB32_90 @ void *to, void *from, int width\r
318 \r
319 vidConvCpyM2_RGB32_90:\r
320     stmfd   sp!, {r4-r10,lr}\r
321 \r
322     mov     lr, #0x00F00000\r
323     orr     lr, lr, #0x00F0\r
324 \r
325     mov     r12, #208/4            @ row counter\r
326     mov     r10, r2, lsl #2        @ we do 2 pixel wide copies\r
327 \r
328     add     r8,  r0, #208*4        @ parallel line\r
329     add     r1,  r1, #0x21000\r
330     add     r1,  r1, #0x00280      @ r1+=328*207*2+8*2\r
331     mov     r9,  r1\r
332 \r
333 .loopM2RGB32_90:\r
334         subs    r12, r12, #1\r
335 \r
336     @ at first this loop was written differently: src pixels were fetched with ldm's and\r
337     @ dest was not sequential. It ran nearly 2 times slower. It seems it is very important\r
338     @ to do sequential memory access on those items, which we have more (to offload addressing bus?).\r
339 \r
340     ldr     r4, [r1], #-328*2\r
341     ldr     r5, [r1], #-328*2\r
342     ldr     r6, [r1], #-328*2\r
343     ldr     r7, [r1], #-328*2\r
344 \r
345     convRGB32_2 r4, 1\r
346     convRGB32_2 r5, 1\r
347     convRGB32_2 r6, 1\r
348     convRGB32_2 r7, 1\r
349 \r
350     str     r4, [r8], #4\r
351     str     r5, [r8], #4\r
352     str     r6, [r8], #4\r
353     str     r7, [r8], #4\r
354 \r
355     bne     .loopM2RGB32_90\r
356 \r
357     subs    r10, r10, #1\r
358     ldmeqfd sp!, {r4-r10,pc}        @ return\r
359 \r
360     mov     r12, #208/4             @ restore row counter\r
361     mov     r0,  r8                 @ set new dst pointer\r
362     add     r8,  r0,  #208*4\r
363     add     r9,  r9,  #2*2          @ fix src pointer\r
364     mov     r1,  r9\r
365     b       .loopM2RGB32_90\r
366 \r
367 \r
368 \r
369 @ converter for vidConvCpyM2_RGB32_270\r
370 @ lr =  0x00F000F0, out: r3=lower_pix, r2=higher_pix; trashes rin\r
371 .macro convRGB32_3 rin\r
372     and     r2,  lr, \rin, lsr #4 @ blue\r
373     and     r3,  \rin, lr\r
374     orr     r2,  r2,   r3, lsl #8         @ g0b0g0b0\r
375 \r
376     mov     r3,  r2,  lsl #16             @ g0b00000\r
377     and     \rin,lr,  \rin, ror #12       @ 00r000r0 (reversed)\r
378     orr     r3,  r3,  \rin, lsr #16       @ g0b000r0\r
379 \r
380     mov     r2,  r2,  lsr #16\r
381     orr     r2,  r2,  \rin, lsl #16\r
382     str     r2, [r0], #4\r
383 \r
384     mov     \rin,r3,  ror #16             @ r3=low\r
385 .endm\r
386 \r
387 \r
388 .global vidConvCpyM2_RGB32_270 @ void *to, void *from, int width\r
389 \r
390 vidConvCpyM2_RGB32_270:\r
391     stmfd   sp!, {r4-r10,lr}\r
392 \r
393     mov     lr, #0x00F00000\r
394     orr     lr, lr, #0x00F0\r
395 \r
396     mov     r12, #208/4            @ row counter\r
397     mov     r10, r2, lsl #2        @ we do 2 pixel wide copies (right to left)\r
398 \r
399     add     r8,  r0, #208*4        @ parallel line\r
400     add     r1,  r1, #326*2\r
401     mov     r9,  r1\r
402 \r
403 .loopM2RGB32_270:\r
404         subs    r12, r12, #1\r
405 \r
406     ldr     r4, [r1], #328*2\r
407     ldr     r5, [r1], #328*2\r
408     ldr     r6, [r1], #328*2\r
409     ldr     r7, [r1], #328*2\r
410 \r
411     convRGB32_3 r4\r
412     convRGB32_3 r5\r
413     convRGB32_3 r6\r
414     convRGB32_3 r7\r
415 \r
416     str     r4, [r8], #4\r
417     str     r5, [r8], #4\r
418     str     r6, [r8], #4\r
419     str     r7, [r8], #4\r
420 \r
421     bne     .loopM2RGB32_270\r
422 \r
423     subs    r10, r10, #1\r
424     ldmeqfd sp!, {r4-r10,pc}        @ return\r
425 \r
426     mov     r12, #208/4             @ restore row counter\r
427     mov     r0,  r8                 @ set new dst pointer\r
428     add     r8,  r0,  #208*4\r
429     sub     r9,  r9,  #2*2          @ fix src pointer\r
430     mov     r1,  r9\r
431     b       .loopM2RGB32_270\r
432 \r