From 7c6bdd64935452464b21f99198896c34569105e5 Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Wed, 23 Jun 2004 22:15:50 +0000 Subject: Split grayscale library into several files to make up a real function library. Significantly decreases binary size for plugins using it. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4802 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/lib/gray_blockfuncs.c | 262 +++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 apps/plugins/lib/gray_blockfuncs.c (limited to 'apps/plugins/lib/gray_blockfuncs.c') diff --git a/apps/plugins/lib/gray_blockfuncs.c b/apps/plugins/lib/gray_blockfuncs.c new file mode 100644 index 0000000000..4eea73a63b --- /dev/null +++ b/apps/plugins/lib/gray_blockfuncs.c @@ -0,0 +1,262 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* Grayscale framework +* Low level block drawing functions +* +* This is a generic framework to use grayscale display within Rockbox +* plugins. It obviously does not work for the player. +* +* Copyright (C) 2004 Jens Arnold +* +* All files in this archive are subject to the GNU General Public License. +* See the file COPYING in the source tree root for full license agreement. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#ifndef SIMULATOR /* not for simulator by now */ +#include "plugin.h" + +#ifdef HAVE_LCD_BITMAP /* and also not for the Player */ +#include "gray.h" + +/* Prototypes */ +static void _writeblock(unsigned char *address, unsigned mask, unsigned bits); +static void _invertblock(unsigned char *address, unsigned mask, unsigned bits); +static void _writeblockfg(unsigned char *address, unsigned mask, unsigned bits); +static void _writeblockbg(unsigned char *address, unsigned mask, unsigned bits); + +/* Block function pointer array */ +void (*_gray_blockfuncs[4])(unsigned char *address, unsigned mask, + unsigned bits) = { + _invertblock, _writeblockfg, _writeblockbg, _writeblock +}; + +/* Write an 8-pixel block, defined by foreground and background pattern. + * Address is the byte in the first bitplane, mask determines which pixels to + * set, and bits determines if the pixel is foreground or background */ +static void _writeblock(unsigned char *address, unsigned mask, unsigned bits) +{ + unsigned long pat_stack[8]; + register unsigned char *end_addr; + register unsigned long *pat_ptr = &pat_stack[8]; + + /* precalculate the bit patterns with random shifts (same RNG as _writepixel, + * see there for an explanation) for all 8 pixels and put them on an + * extra stack */ + asm ( + "mov #8,r3 \n" /* loop count in r3: 8 pixels */ + "mov %6,r2 \n" /* copy mask */ + + ".wb_loop: \n" /** load pattern for pixel **/ + "shlr r2 \n" /* shift out lsb of mask */ + "bf .wb_skip \n" /* skip this pixel */ + + "mov %2,r4 \n" /* load foreground pattern */ + "shlr %7 \n" /* shift out lsb of bits */ + "bt .wb_fg \n" /* foreground? -> skip next insn */ + "mov %3,r4 \n" /* load background pattern */ + ".wb_fg: \n" + + "mov #75,r0 \n" + "mulu r0,%0 \n" /* multiply by 75 */ + "sts macl,%0 \n" + "add #74,%0 \n" /* add another 74 */ + /* Since the lower bits are not very random: */ + "swap.b %0,r1 \n" /* get bits 8..15 (need max. 5) */ + "and %5,r1 \n" /* mask out unneeded bits */ + + "cmp/hs %4,r1 \n" /* random >= depth ? */ + "bf .wb_ntrim \n" + "sub %4,r1 \n" /* yes: random -= depth; */ + ".wb_ntrim: \n" + + "mov.l .ashlsi3,r0 \n" /** rotate pattern **/ + "jsr @r0 \n" /* r4 -> r0, shift left by r5 */ + "mov r1,r5 \n" + + "mov %4,r5 \n" + "sub r1,r5 \n" /* r5 = depth - r1 */ + "mov.l .lshrsi3,r1 \n" + "jsr @r1 \n" /* r4 -> r0, shift right by r5 */ + "mov r0,r1 \n" /* store previous result in r1 */ + + "bra .wb_store \n" + "or r1,r0 \n" /* rotated_pattern = r0 | r1 */ + + ".wb_skip: \n" + "shlr %7 \n" /* shift out lsb of bits to keep in sync */ + "mov #0,r0 \n" /* pattern for skipped pixel must be 0 */ + + ".wb_store: \n" + "mov.l r0,@-%1 \n" /* push on pattern stack */ + + "add #-1,r3 \n" /* decrease loop count */ + "cmp/pl r3 \n" /* loop count > 0? */ + "bt .wb_loop \n" /* yes: loop */ + : /* outputs */ + /* %0, in & out */ "+r"(_gray_random_buffer), + /* %1, in & out */ "+r"(pat_ptr) + : /* inputs */ + /* %2 */ "r"(_graybuf->fg_pattern), + /* %3 */ "r"(_graybuf->bg_pattern), + /* %4 */ "r"(_graybuf->depth), + /* %5 */ "r"(_graybuf->randmask), + /* %6 */ "r"(mask), + /* %7 */ "r"(bits) + : /* clobbers */ + "r0", "r1", "r2", "r3", "r4", "r5", "macl" + ); + + end_addr = address + MULU16(_graybuf->depth, _graybuf->plane_size); + + /* set the bits for all 8 pixels in all bytes according to the + * precalculated patterns on the pattern stack */ + asm volatile ( + "mov.l @%3+,r1 \n" /* pop all 8 patterns */ + "mov.l @%3+,r2 \n" + "mov.l @%3+,r3 \n" + "mov.l @%3+,r8 \n" + "mov.l @%3+,r9 \n" + "mov.l @%3+,r10 \n" + "mov.l @%3+,r11 \n" + "mov.l @%3+,r12 \n" + + "not %4,%4 \n" /* "set" mask -> "keep" mask */ + "extu.b %4,%4 \n" /* mask out high bits */ + "tst %4,%4 \n" /* nothing to keep? */ + "bt .wb_sloop \n" /* yes: jump to short loop */ + + ".wb_floop: \n" /** full loop (there are bits to keep)**/ + "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */ + "rotcl r0 \n" /* rotate t bit into r0 */ + "shlr r2 \n" + "rotcl r0 \n" + "shlr r3 \n" + "rotcl r0 \n" + "shlr r8 \n" + "rotcl r0 \n" + "shlr r9 \n" + "rotcl r0 \n" + "shlr r10 \n" + "rotcl r0 \n" + "shlr r11 \n" + "rotcl r0 \n" + "shlr r12 \n" + "mov.b @%0,%3 \n" /* read old value */ + "rotcl r0 \n" + "and %4,%3 \n" /* mask out unneeded bits */ + "or r0,%3 \n" /* set new bits */ + "mov.b %3,@%0 \n" /* store value to bitplane */ + "add %2,%0 \n" /* advance to next bitplane */ + "cmp/hi %0,%1 \n" /* last bitplane done? */ + "bt .wb_floop \n" /* no: loop */ + + "bra .wb_end \n" + "nop \n" + + ".wb_sloop: \n" /** short loop (nothing to keep) **/ + "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */ + "rotcl r0 \n" /* rotate t bit into r0 */ + "shlr r2 \n" + "rotcl r0 \n" + "shlr r3 \n" + "rotcl r0 \n" + "shlr r8 \n" + "rotcl r0 \n" + "shlr r9 \n" + "rotcl r0 \n" + "shlr r10 \n" + "rotcl r0 \n" + "shlr r11 \n" + "rotcl r0 \n" + "shlr r12 \n" + "rotcl r0 \n" + "mov.b r0,@%0 \n" /* store byte to bitplane */ + "add %2,%0 \n" /* advance to next bitplane */ + "cmp/hi %0,%1 \n" /* last bitplane done? */ + "bt .wb_sloop \n" /* no: loop */ + + ".wb_end: \n" + : /* outputs */ + : /* inputs */ + /* %0 */ "r"(address), + /* %1 */ "r"(end_addr), + /* %2 */ "r"(_graybuf->plane_size), + /* %3 */ "r"(pat_ptr), + /* %4 */ "r"(mask) + : /* clobbers */ + "r0", "r1", "r2", "r3", "r8", "r9", "r10", "r11", "r12" + ); +} + +/* References to C library routines used in _writeblock */ +asm ( + ".align 2 \n" +".ashlsi3: \n" /* C library routine: */ + ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */ +".lshrsi3: \n" /* C library routine: */ + ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */ + /* both routines preserve r4, destroy r5 and take ~16 cycles */ +); + +/* Invert pixels within an 8-pixel block. + * Address is the byte in the first bitplane, mask and bits determine which + * pixels to invert ('And'ed together, for matching the parameters with + * _writeblock) */ +static void _invertblock(unsigned char *address, unsigned mask, unsigned bits) +{ + bits &= mask; + if (!bits) + return; + + asm volatile ( + "mov #0,r1 \n" /* current_plane = 0 */ + + ".im_loop: \n" + "mov.b @%1,r2 \n" /* get data byte */ + "add #1,r1 \n" /* current_plane++; */ + "xor %2,r2 \n" /* invert bits */ + "mov.b r2,@%1 \n" /* store data byte */ + "add %3,%1 \n" /* advance address to next bitplane */ + "cmp/hi r1,%0 \n" /* current_plane < depth ? */ + "bt .im_loop \n" + : /* outputs */ + : /* inputs */ + /* %0 */ "r"(_graybuf->depth), + /* %1 */ "r"(address), + /* %2 */ "r"(bits), + /* %3 */ "r"(_graybuf->plane_size) + : /* clobbers */ + "r1", "r2", "macl" + ); +} + +/* Call _writeblock with the mask modified to draw foreground pixels only */ +static void _writeblockfg(unsigned char *address, unsigned mask, unsigned bits) +{ + mask &= bits; + if (mask) + _writeblock(address, mask, bits); +} + +/* Call _writeblock with the mask modified to draw background pixels only */ +static void _writeblockbg(unsigned char *address, unsigned mask, unsigned bits) +{ + mask &= ~bits; + if (mask) + _writeblock(address, mask, bits); +} + +#endif // #ifdef HAVE_LCD_BITMAP +#endif // #ifndef SIMULATOR + -- cgit v1.2.3