Search

Technical Discussion Group Forum

This forum is provided for user discussion. While Beacon EmbeddedWorks support staff and engineers participate, Beacon EmbeddedWorks does not guarantee the accuracy of all information within in the Technical Discussion Group (TDG).

The "Articles" forums provide brief Articles written by Beacon EmbeddedWorks engineers that address the most frequently asked technical questions.

To receive email notifications when updates are posted for a Beacon EmbeddedWorks product download, please subscribe to the TDG Forum of interest.

TDG Forum

PrevPrev Go to previous topic
NextNext Go to next topic
Last Post 27 Feb 2008 07:44 AM by  tombrus
how can I enable the floating point co-processor
 4 Replies
Sort:
You are not authorized to post a reply.
Author Messages
tombrus
New Member
New Member
Posts:


--
22 Feb 2008 03:22 AM
    Hi,

    I have got my LiteKit with floating point i.MX31 sitting on my desk. My first goal is to see if our floating point algorithm can be run fast enough on this board. I would like to compile our core algorithm (in C) and load this in my board with lolo "load elf/jump".

    I took my first hurdle in building my own gnu toolchain with fp enabled. That gave me compiled code with fp instructions. yeah! This, however, does not run because I get a
    Quote:
    Unhandled Exception:
    exception mode: undef
    I figured out that this is probably because the FP-coprocessor is not enabled yet. That could be done with
    Quote:
    MOV r0,#0x40000000"
    FMXR FPEXC, r0"
    but the FMXR also gives me an undef exception. Probably because I am not in SVC mode. I have not found a simple way to switch to SVC mode (This is probably by design, because you do not want easy usr->svc mode switches ) I found the "Application Note 133 - Using VFP with RVDS" but that seems a hefty amount of code for a simple task. Furthermore I do not know if all this applies 1-to-1 to my LiteKit board. (e.g. the 0x4 location for the undef exception vector does not seem to be valid).

    So how can I start using my FP unit?

    I found that lolo has a command called 'mcr' that does something with co-processor registers, but I could not find any more info than this:
    Quote:
    usage:
    mcr mcr <coproc> <opcode 1> <value> <CRn> <CRm> <opcode_2>

    set coprocessor register value

    example: mcr p15 0 0 c1 c0 0
    Could I use this to enable my fp coprocessor?

    In general, could somebody give me a hint as where to find documentation on the ARM instruction set and the details on how the internal peripherals are layed out and how they can be programed Maybe I am a bad googler, but I spend a lot of time and only found fragments of info.

    All help is appreciated.

    Regards,
    Tom Brus
    spannring
    New Member
    New Member
    Posts:


    --
    25 Feb 2008 12:09 PM
    As you noticed, the LogicPD supplied GCC toolchain doesn't (or at least didn't as of last Fall) support the VFP unit. When I compiled a GCC toolchain with VFP support everything worked fine for me.

    I'm almost wondering if you had all the command line options correct when you compiled the tool chain. There's a thread titled "Problem using the floating point unit" at

    http://tdg.logicpd.com/viewtopic.php?f=29&t=1271

    that might help.
    tombrus
    New Member
    New Member
    Posts:


    --
    25 Feb 2008 01:39 PM
    That is strange, your code just runs fine? hmmm, what lolo version do you use? I'll check mine tomorrow, I do not have the board at hand here now.

    The post you mention is exactly what helped me to compile the tool chain, and indeed the (new) compiler spits out vfp instructions. The problem is that when I 'lolo-jump' to that code the first vfp instruction that is hit just trap into lolo's exception handler and -bang- the board is stuck.

    Might you have linked in some lib code that silently enabled the vfp for you? Can you elaborate a bit more on your software setup?

    Oh, and thanks for replying
    spannring
    New Member
    New Member
    Posts:


    --
    26 Feb 2008 09:44 AM
    Not sure what could be different except that I use the exec command instead of jump. exec does some reconfiguration of the CPU before it jumps to the specified address. You could try exec, but to be honest, I'm not sure what the cause of the problem really is.
    tombrus
    New Member
    New Member
    Posts:


    --
    27 Feb 2008 07:44 AM
    YEAH! I got it running . Thanks spanning for your reactions. Better share this with the community:

    It took some digging but (as always) the solution was trivial: I had to enable the FP co-processor. I thought this was done by the "FMXR FPEXC, r0" instruction, but that was not the whole story. That instruction is for enabling the VFP after it the whole co-processor has been switched on. This was the piece of the puzzle that was missing. All co-processors can be enabled in the "Coprocessor access register". Each co-processor has two bits to enable it for SVC and/or user mode. The VFP is co-processor cp10 and cp11. The register can be accessed with "mcr p15, 0, r0, c1, c0, 2". To wrap it all together, the following C function will enable the VFP:
    void ENABLE_VFP (void) {
    asm(" mrc p15, 0, r0, c1, c0, 2");
    asm(" orr r0, r0, #(0xf << 20)");
    asm(" mcr p15, 0, r0, c1, c0, 2");
    asm(" mov r0, #0x40000000");
    asm(" fmxr fpexc, r0");
    }
    The first three instructions switch the co-processor on while the last two enable the VFP itself.

    Be aware that this will only work if you have a single process using the VFP. I used it for a "led_flasher" type of program.

    Regards,
    Tom

    P.S. I had to do a lot of trial and error to get the above. Because the LEDs on the board were a bit too simple to get sensible feed back I implemented a simple printf. I thought I might as well share it with you. Remarks: it is completely synchronous; it should only be used for debugging; I needed a delay loop for every character otherwise I would loose characters (it might be due to my host machine so try to take it out if you want to); I used some code I found on the web by "Georges Menie", he deserves 99% of the credits . I hope this will help others.

    #define UART (0x43f90040)
    struct uart
    { volatile unsigned dr; // @0x0
    volatile unsigned ecr; // @0x4
    volatile unsigned lcrh; // @0x8
    volatile unsigned lcrm; // @0x0c
    volatile unsigned lcrl; // @0x10
    volatile unsigned cr; // @0x14
    volatile unsigned fr; // @0x18
    volatile unsigned iir; // @0x1C
    volatile unsigned ilpr; // @0x20
    volatile unsigned ibrd; // @0x24
    volatile unsigned fbrd; // @0x28
    volatile unsigned lcrh11; // @0x2C
    volatile unsigned cr11; // @0x30
    };

    #define FR_RX_Fifo_Empty 0x10
    #define FR_TX_Fifo_Full 0x20
    #define FR_RX_Fifo_Full 0x40
    #define FR_TX_Fifo_Empty 0x80

    struct uart *uart0 = (struct uart*)UART;

    #define DELAY (5000)
    unsigned int counter;

    void toUart(char c) {
    while (uart0->fr & FR_TX_Fifo_Full)
    ;
    for (counter = DELAY; counter; counter--);
    uart0->dr = (unsigned char) c;
    }

    char toHex(char c) {
    if (c>9) {
    return 'a'+(c-10);
    } else {
    return '0'+c;
    }
    }

    void putchar(char c) {
    if (c == '\n') {
    toUart('\r');
    }
    toUart(c);
    /*
    toUart('(');
    toUart('=');
    toUart('0');
    toUart('x');
    toUart(toHex((c>>4)&0x0f));
    toUart(toHex( c &0x0f));
    toUart(')');
    toUart(' ');
    */
    }

    /*
    Copyright 2001, 2002 Georges Menie (www.menie.org)
    stdarg version contributed by Christian Ettinger

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    */

    /*
    putchar is the only external dependency for this file,
    if you have a working putchar, leave it commented out.
    If not, uncomment the define below and
    replace outbyte(c) by your own function call.

    #define putchar(c) outbyte(c)
    */

    #include <stdarg.h>

    static void printchar(char **str, int c) {
    if (str) {
    **str = c;
    ++(*str);
    } else {
    putchar(c);
    }
    }

    #define PAD_RIGHT 1
    #define PAD_ZERO 2

    static int prints(char **out, const char *string, int width, int pad)
    {
    register int pc = 0, padchar = ' ';

    if (width > 0) {
    register int len = 0;
    register const char *ptr;
    for (ptr = string; *ptr; ++ptr) ++len;
    if (len >= width) width = 0;
    else width -= len;
    if (pad & PAD_ZERO) padchar = '0';
    }
    if (!(pad & PAD_RIGHT)) {
    for ( ; width > 0; --width) {
    printchar (out, padchar);
    ++pc;
    }
    }
    for ( ; *string ; ++string) {
    printchar (out, *string);
    ++pc;
    }
    for ( ; width > 0; --width) {
    printchar (out, padchar);
    ++pc;
    }

    return pc;
    }

    /* the following should be enough for 32 bit int */
    #define PRINT_BUF_LEN 12

    static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase)
    {
    char print_buf[PRINT_BUF_LEN];
    register char *s;
    register int t, neg = 0, pc = 0;
    register unsigned int u = i;

    if (i == 0) {
    print_buf[0] = '0';
    print_buf[1] = '\0';
    return prints (out, print_buf, width, pad);
    }

    if (sg && b == 10 && i < 0) {
    neg = 1;
    u = -i;
    }

    s = print_buf + PRINT_BUF_LEN-1;
    *s = '\0';

    while (u) {
    t = u % b;
    if( t >= 10 )
    t += letbase - '0' - 10;
    *--s = t + '0';
    u /= b;
    }

    if (neg) {
    if( width && (pad & PAD_ZERO) ) {
    printchar (out, '-');
    ++pc;
    --width;
    }
    else {
    *--s = '-';
    }
    }

    return pc + prints (out, s, width, pad);
    }

    static int print(char **out, const char *format, va_list args )
    {
    register int width, pad;
    register int pc = 0;
    char scr[2];

    for (; *format != 0; ++format) {
    if (*format == '%') {
    ++format;
    width = pad = 0;
    if (*format == '\0') break;
    if (*format == '%') goto out;
    if (*format == '-') {
    ++format;
    pad = PAD_RIGHT;
    }
    while (*format == '0') {
    ++format;
    pad |= PAD_ZERO;
    }
    for ( ; *format >= '0' && *format <= '9'; ++format) {
    width *= 10;
    width += *format - '0';
    }
    if( *format == 's' ) {
    register char *s = (char *)va_arg( args, int );
    pc += prints (out, s?s:"(null)", width, pad);
    continue;
    }
    if( *format == 'd' ) {
    pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a');
    continue;
    }
    if( *format == 'x' ) {
    pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a');
    continue;
    }
    if( *format == 'X' ) {
    pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A');
    continue;
    }
    if( *format == 'u' ) {
    pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a');
    continue;
    }
    if( *format == 'c' ) {
    /* char are converted to int then pushed on the stack */
    scr[0] = (char)va_arg( args, int );
    scr[1] = '\0';
    pc += prints (out, scr, width, pad);
    continue;
    }
    }
    else {
    out:
    printchar (out, *format);
    ++pc;
    }
    }
    if (out) **out = '\0';
    va_end( args );
    return pc;
    }

    int printf(const char *format, ...)
    {
    va_list args;

    va_start( args, format );
    return print( 0, format, args );
    }

    int sprintf(char *out, const char *format, ...)
    {
    va_list args;

    va_start( args, format );
    return print( &out, format, args );
    }

    #ifdef TEST_PRINTF
    void test() {
    char *ptr = "Hello world!";
    char *np = 0;
    int i = 5;
    unsigned int bs = sizeof(int)*8;
    int mi;
    char buf[80];

    mi = (1 << (bs-1)) + 1;

    printf("%s\n", ptr);
    printf("printf test\n");
    printf("%s is null pointer\n", np);
    printf("%d = 5\n", i);
    printf("%d = - max int\n", mi);
    printf("char %c = 'a'\n", 'a');
    printf("hex %x = ff\n", 0xff);
    printf("hex %02x = 00\n", 0);
    printf("signed %d = unsigned %u = hex %x\n", -3, -3, -3);
    printf("%d %s(s)%", 0, "message");
    printf("\n");
    printf("%d %s(s) with %%\n", 0, "message");
    sprintf(buf, "justif: \"%-10s\"\n", "left"); printf("%s", buf);
    sprintf(buf, "justif: \"%10s\"\n", "right"); printf("%s", buf);
    sprintf(buf, " 3: %04d zero padded\n", 3); printf("%s", buf);
    sprintf(buf, " 3: %-4d left justif.\n", 3); printf("%s", buf);
    sprintf(buf, " 3: %4d right justif.\n", 3); printf("%s", buf);
    sprintf(buf, "-3: %04d zero padded\n", -3); printf("%s", buf);
    sprintf(buf, "-3: %-4d left justif.\n", -3); printf("%s", buf);
    sprintf(buf, "-3: %4d right justif.\n", -3); printf("%s", buf);
    }

    /*
    * if you compile this file with
    * gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -c printf.c
    * you will get a normal warning:
    * printf.c:214: warning: spurious trailing `%' in format
    * this line is testing an invalid % at the end of the format string.
    *
    * this should display (on 32bit int machine) :
    *
    * Hello world!
    * printf test
    * (null) is null pointer
    * 5 = 5
    * -2147483647 = - max int
    * char a = 'a'
    * hex ff = ff
    * hex 00 = 00
    * signed -3 = unsigned 4294967293 = hex fffffffd
    * 0 message(s)
    * 0 message(s) with %
    * justif: "left "
    * justif: " right"
    * 3: 0003 zero padded
    * 3: 3 left justif.
    * 3: 3 right justif.
    * -3: -003 zero padded
    * -3: -3 left justif.
    * -3: -3 right justif.
    */
    #endif
    You are not authorized to post a reply.