C4x TODO

Development

  1. The most important thing to do is to get all the C4x patches included into the mainstream distributions.

  2. The next most important task is the updating of the documentation and writing of new documentation.

  3. Porting or writing the C and math libraries libc.a and libm.a (one could try glibc-2.0 as a basis but it appears that newlib (available from ftp.cygnus.com) will be a lot easier).

    Ideally the C library should have an OS independent syscall interface and the math libraries should be written entirely in C, using inline assembly for speed critical bits and the C preprocessor to handle processor variations.

    For example, here are implementations of the functions ldexp() and frexp() I have written:

    static inline int d2exp(double x)
    {
        register int ret;
        asm volatile("pushf\t%1\n" \
    	         "\tpop\t%0\n" \
    		 "\tash\t-24,%0\n"\
    		  : "=f" (ret) \
    		  : "g" (x) \
    		  : "cc");
        return ret;
    }
    
    static inline double exp2d(int exp)
    {
        register double ret;
        asm volatile("ash\t24,%1\n"\
    		 "\tpush\t%1\n" \
    	         "\tpopf\t%0\n" \
    		  : "=f" (ret) \
    		  : "g" (exp) \
    		  : "cc");
        return ret;
    }
    
    static inline double lde(double src, double dst)
    {
        asm volatile("lde\t%2,%0\n"\
    		  : "=f" (dst) \
    		  : "0" (dst), "g" (src) \
    		  );
        return dst;
    }
    
    double ldexp(double x, int exp)
    {
        /* We don't check for overflow, or set errno */
        exp += d2exp(x);
        return lde(exp2d(exp), x);
    }
    
    double frexp(double x, int *exp)
    {
        double ret;
        int e;
        
        if (x == 0.0)
        {
    	*exp = 0;
    	return 0.0;
        }
        e = d2exp(x) + 1;
        if ((ret = lde(0.5, x)) == -1.0)
        {
    	*exp = e + 1;
    	return -0.5;
        }
        *exp = e;
        return ret;
    }
    	

Bugs to Fix

  1. Fix compiler and assembler to include additional C32 opcodes and addressing modes for parallel instructions found on the newer silicon dies (starting with PG 6, marked on the chips as xE-xxxx). Maybe we should have -mpg option?

  2. Disallow use of non extended precision registers with floating point instructions in the assembler.

  3. objdump doesn't print absf r0, r0 (this instruction is all zeroes and md_disassemble() is not called for this instruction). This is a bug in objdump.c

  4. ld needs configuring to properly tag object files for the C30. The assembler properly tags C30 object files but the linker defaults the executable file to be for the C40. Note that the code is OK, but the disassembler (objdump/gdb) can get confused.

  5. The disassembler may print inaccurate floating point numbers with some hosts (the floating point printing code needs to be rewritten to be independent of host floating point capability.)


Enhancements

  1. GCC support for circular addressing, say by using a qualifier keyword such as __circ__.

  2. GCC support for internal memory to improve instruction scheduling, say by using a qualifier keyword such as __internal__.

  3. Improved GCC register saving in interrupt service routines (ISRs) (see gcc/config/c4x/c4x.c).

    Currently if the ISR is a leaf function (i.e., it does not call any non-inlined functions, the ISR prologue pushes all the registers used by the ISR. Similarly, the ISR epilogue pops the used registers.

    Now if the ISR calls an external function, the prologue has to push all the registers that may possibly be used by the external function, requiring a much greater overhead.

    Often, however, an ISR that calls an external function may only have to so only when a buffer is full, or when it is time in a multitasking system to preempt the current task. Most of the time this external function is never called and it is a considerable overhead to have to allow for this worst case scenario when all you want your ISR to do is to quickly read a sample and to stick it into a buffer. For example, consider the following pseudo-code:

    #define __interrupt__ __attribute__ ((interrupt)) 
    static void __interrupt__ void isr(void)
    {
       <ISR prologue>
       Save context required by ISR (not including context possibly
       required by the external function).
    
       <ISR interrupt servicing>  
    
       if (exceptional_condition)
       {
           Save additional context possibly required by external function.
           Call external function
           Restore additional context possibly required by external function.
       }
    
       <ISR epilogue>
       Restore context required by ISR (not including context possibly
       required by the external function).
    }
    	

    One possible simple solution, is to get the called external function to save the context it knows it requires, although this can lead to duplication of context saving.

    The current hack is to define the attribute leaf_pretend for the ISR. You will then be responsible for saving/restoring the additional context yourself.


Copyright ©1997,1998,1999,2000,2001 Michael Hayes (m.hayes@elec.canterbury.ac.nz)

Last modified: Sat Jun 16 16:43:52 NZST 2001