Shop OBEX P1 Docs P2 Docs Learn Events
C4SX: Optional patch to allow direct insertion of SX assembler directives and o — Parallax Forums

C4SX: Optional patch to allow direct insertion of SX assembler directives and o

RW SenserRW Senser Posts: 61
edited 2007-07-31 18:23 in General Discussion

Greetings.· If you a C programmer and·C4SX user, you might be interested in this posting.

Attached is a patch to the just-released C4SX version that makes it possible to insert SX assembler code·into the generated SX code (from the CC1B C compiler).· This added capability is enabled by the CC1B2SX converter program.· The included readme file describes how to install it.
·
We did a lot of testing to see which approach worked best -- many suggestions and ideas were given on this forum.· Thanks to all who gave us input.· We decided to go with the simple approach of using two literals to mark the beginning and end of the code to be inserted directly from the C code.·
·
Here are two code snippets from the included ledc28v2.c program:
·
/*<?asm
·DEVICE OSCHS3
·IRC_CAL IRC_FAST
·FREQ·50_000_000
·RESET·main
·ID·'project'
?>*/
·
·· ·/*<?asm
··not RB
··?>*/
·
See the sample program for more details.
·
We tried using the #pragma sx approach, the #asm .. #endasm approach and several others C MACRO-based approaches.· None of them worked well.· This approach with /*<?asm and ?>*/ is the cleanest in the sense that it is clear what is going on.· The source code for CC1B2SX is included.· C programmers can change this to use other literals if they wish.
·
If anyone has problems with this patch, please let us know!

Again, many thanks for the feedback!!
·
Thanks,
RW Senser

Comments

  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-26 23:29
    This works great!
    Just one thing, how do I prevent the insertion of the header file?
    (I now have everything in the header file commented out).

    regards peter
  • RW SenserRW Senser Posts: 61
    edited 2007-07-26 23:37
    Hi peter,

    Glad you like it!

    Two easy ways to avoid the header file:
    1) Delete or rename the CC1B2SX.HDR file. It missing will not bother the CC1B2SX utility.
    2) Put c:\C4SX in your Windows PATH and then work from a different diretory that contains your source but not the CC1B2SX.HDR file. This is requently the way I work.

    To set the Windows PATH (in case anyone does not know this...), from the command line:

    set PATH=%PATH%;C:\C4SX

    Thanks,
    RW Senser
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-26 23:49
    I will rename the header file, but in my opinion
    you should make a·new release without the header file.
    To keep it simple just demand that each main C file starts with

    #pragma chip SX28 // select device
    /*<?asm
    ·DEVICE OSCHS3
    ·IRC_CAL IRC_FAST
    ·FREQ·50_000_000
    ·RESET·main
    ·ID·'project'
    ?>*/

    People can simply set the directives or commenting them out by placing a ; in front of them.

    regards peter


    Post Edited (Peter Verkaik) : 7/26/2007 11:56:33 PM GMT
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-27 00:09
    Can you produce a list of variable/function names that should not
    be used in a C file because they conflict with SASM reserved keywords?

    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-27 13:16
    What cc1b lacks are libraries. So I converted a few of my javelin classes
    to cc1b libraries. These are the standard string and character functions
    (stdlib.h, ctype.h and string.h)
    All library functions compile without error. I do not claim they are optimized
    so if anyone optimizes some functions, please report that.
    You can place those libraries in the cc1b installation directory, after
    which you can use (using string.h as example)
    #include <string.h>
    in your C source.

    Libraries are just C files, but all code is enclosed in
    #pragma library 1
    //code goes here
    #pragma library 0

    While finding out how libraries were to be created, I checked the math16.h library.
    It appears cc1b supports operator overloading. This is quite useful as that will
    allow us to use the +,-,* and /·characters to add,sub,mul and div two userdefined datatypes. I·did that once
    for the javelin using the subjava package.·(for example·matrix math or complex numbers).

    Now I will try to convert my Virtual Peripheral library to cc1b.

    Edit: inserted conditional compile statements in the libraries so libraries can be included
    many times without generating compile errors. So a library file looks like
    #ifndef _LIBNAME_H_
    #define _LIBNAME_H_
    //include other libraries here
    #pragma library 1
    //library code goes here
    #pragma library 0
    #endif

    The library stdlib.h for example needs functions from ctype.h, so stdlib.h now includes ctype.h.
    If you don't need functions from ctype.h in your main C file, you don't need to include it if
    you only require library stdlib.h, but if you do include it, there will be no compilation errors.


    regards peter

    Post Edited (Peter Verkaik) : 7/28/2007 9:58:18 AM GMT
  • RW SenserRW Senser Posts: 61
    edited 2007-07-29 01:32
    Hi Peter,

    Greetings.

    I'm planning on recutting a C4SX release in the next days. I expect to have better documentation, a good sample serial (SXIO.H) program, the patch just released and some other minor items.

    Can I include your include files? (with due credit given in the "Contributions and Credits" section)

    It has been suggested that we add an edit to the CC1B2SX converted, using a list of reserved words like you mentioned, to flag any invalid names found at convert time. Thoughts? I suspect this is matter of starting with a best-guess list and then adding to it as more becomes known.

    Thanks for your efforts!

    Thanks,
    RW Senser
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-29 02:36
    RW Sensor,
    Of course you can include the libraries.
    A list of reserved keywords in a seperate file is preferable.
    If you can throw a message at convert time which names used
    in the C file are in conflict with SASM, that would be great.
    We can then simply rename these in the C file without
    first assembling to find out about it.

    regards peter
  • RW SenserRW Senser Posts: 61
    edited 2007-07-29 18:01
    Hi Peter,
    Attached is a zip file with a C program that uses your new libs and my older SXIO.H.· The program is called sxstring.c.·· When I started mixing the various libs together, I started to hit some issues plus I found an area you might want to change in your string functions for input strings.

    If you compare your originals with the string2.h and stdlib2.h in the zip file, you can see the differences.· I used windiff to compare them.· Summary of changes:

    I moved some variables to 'shrBank'.· If you try to compile sxstring.c, with sxio.h present and the original string.h and stdlib.b present, you can see the errors.· The problem is all the code is trying to use the easy-to-use shared storage at locations 0x8 to oxf.

    I also changed some call parameters from 'char *' to 'const char *'.· This makes it possible to access strings (char arrays) that are constant, and therefore not in RAM.

    sxio.h needs to be included first as it contains an interrupt handler.· I need to add library 1, etc. pragma to it and find a way to move it's non 0x8 to 0xf around.· Right now it goes in bank 1.· I think I might set it for bank 7.

    In summary, with a little tuning we should be able to·produce libs·that use less of the really limited shrBank (0x8 to 0xf) memory and make it possible for these to coexist with larger C·programs.

    These libs are really great!· I've not found a single bug!

    Maybe we should exchange a few direct emails/messages to sort these lib sizing and location issues out.

    Thanks,
    RWSenser
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-29 18:39
    RW Senser,

    I was playing around with the memory map that cc1b generates.
    "#pragma rambank -" sets the base of the ram allocated for globals and locals
    to the Mapped Ram ($00-$0F) (aka SharedRam)
    "#pragma rambank 1" sets the base of the ram allocated for globals and locals
    to rambank 1 ($10-$1F), etc for 2-15
    "#pragma rambank 0" sets the base of the ram allocated for globals and locals
    to rambank 0 (SX48/52 only, $100-$10F)

    My libraries use only locals and should therefor·not be restricted in which library comes
    first, but that will require a #pragma rambank 1 in the C main file (so no mapped ram
    is used for locals).
    I also noted cc1b always allocates rambank 7 ($70-$7F) and I have not yet found
    out to what (data stack perhaps?).

    There is also "#pragma rambase xx" but I am not quite sure about the difference between
    rambank and rambase. I think we should first have a clear understanding how cc1b
    deals exactly with globals and locals. I use the cc5x manual as guideline but cc1b
    may differ slightly in some cases.

    Edit:
    The ram locations $70-$7F that were always allocated, was due to a test library that
    I included in my test C file.
    Tip: I added -V to the compile commands in C4SX.bat
    This makes cc1b generate a variable file <src>.var that holds a detailed variable listing.

    regards peter

    Post Edited (Peter Verkaik) : 7/29/2007 8:07:54 PM GMT
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-29 22:39
    I figured out how cc1b allocates ram to variables.
    See attached text file for a summary on allocation.
    Since rambank1 for sx18/20/28 represents another ram area than rambank1 for sx48/52
    I added a #define to the 5 header files for chiptypes. (attached zip file).
    chip sx18: added #define _CHIP_SX18_
    chip sx20: added #define _CHIP_SX20_
    chip sx28: added #define _CHIP_SX28_
    chip sx48: added #define _CHIP_SX48_
    chip sx52: added #define _CHIP_SX52_
    These allow us to do conditional compilation based on chiptype, eg
    #ifdef _CHIP_SX18_
    //sx18 specific code
    #endif

    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-30 16:47
    RW Senser,

    I have written 4 very small routines that will allow large arrays to be used
    on the sx18/20/28 (the sx48/52 allow it natively). These are located in library
    memory.h that goes into the cc1b directory. For convenience and to allow code
    to be compiled for sx18/20/28 as well as sx48/52 there are also identical named
    routines for the sx48/52.

    Secondly, I introduced new rambank pragma's (called membank0 to membank16)
    which are clearer because there is a direct relation between the membank number
    and the physical addresses (membank1 represents 0x10-0x1F, membank8 represents 0x80-0x8F etc)
    For the sx18/20/28 I defined
    #define membank0 rambank -
    #define membank1 rambank 0
    #define membank2 rambank -1
    #define membank3 rambank 1
    #define membank4 rambank -1
    #define membank5 rambank 2
    #define membank6 rambank -1
    #define membank7 rambank 3
    #define membank8 rambank -1
    #define membank9 rambank 4
    #define membank10 rambank -1
    #define membank11 rambank 5
    #define membank12 rambank -1
    #define membank13 rambank 6
    #define membank14 rambank -1
    #define membank15 rambank 7
    #define membank16 rambank -1
    For the sx48/52 I defined
    #define membank0 rambank -
    #define membank1 rambank 1
    #define membank2 rambank 2
    #define membank3 rambank 3
    #define membank4 rambank 4
    #define membank5 rambank 5
    #define membank6 rambank 6
    #define membank7 rambank 7
    #define membank8 rambank 8
    #define membank9 rambank 9
    #define membank10 rambank 10
    #define membank11 rambank 11
    #define membank12 rambank 12
    #define membank13 rambank 13
    #define membank14 rambank 14
    #define membank15 rambank 15
    #define membank16 rambank 0
    Unavailable membank's on the sx18/20/28 are set to rambank -1
    so these generate a compiler error when used on the sx18/20/28.
    Instead of using
    #pragma rambank 1
    you use
    #pragma membank1
    membank0 always represents 0x00-0x0F (global ram), no matter what chip is used.

    Thirdly, I defined a char array that includes all ram memory, except bank0 for the sx48/52
    (bank0 uses semi-direct addressing so it cannot be indexed)
    I did that using the shadowDef modifier (does not affect variable allocation)

    shadowDef char _SystemRam[noparse][[/noparse]256] @0x00;
    This works the same as __RAM() in sx/b and really is handy for manipulating memory.

    Library memory.h uses that array to access large arrays.
    The testprogram shows an example of an array crossing rambank boundaries on a sx28.
    You can run this program with SxSim.

    regards peter

    Post Edited (Peter Verkaik) : 7/30/2007 4:57:45 PM GMT
  • RW SenserRW Senser Posts: 61
    edited 2007-07-31 01:51
    Hi Peter,

    Greetings. I'm in the process of cutting a next C4SX (upgrading sample programs, changing CC1B2SX, etc.) and reading through you changes to the header files. I'd like to ponder your changes overnight. I'm thinking of asking the CC1B author to add the _CHIP_SX<whatever>_ settings to his header files as these MACROs are clearly valuable -- and an easy change to make. I'm less certain about membank<whatever> MACROs; these could be added in a second header (if the _CHIP_SX_ is set). So, let me ponder here.

    And a request/question back to you:

    Most important: Thanks for the nice libraries -- they work well.

    And, of course, a suggested change:

    The way the your string.h and stdlib.h are currently written, it is an error to do this:

    static const char lit1 = "C4";
    result2 = strlen(lit1);

    Error:
    result2 = strlen(lit1);
    ^
    Error sxstring.c 117: Incompatible storage classes (const needed)
    (A RAM pointer can not be assigned a const pointer or const data addresses)

    If functions like strlen where changed:
    FROM:

    /**
    * return length of string s (fast version)
    */
    int strlen(char *s) {
    char n = 0;
    while (*s) {
    s++;
    n++;
    }
    return (n);
    }

    TO:
    /**
    * return length of string s (fast version)
    */
    int strlen(const char *s) {
    char n = 0;
    while (*s) {
    s++;
    n++;
    }
    return (n);
    }

    then no error (and correct retsults). In other words, in the prototype mark input parameters as const.

    I think being able to use strings as constants is very important on the SX, since the RAM/register memory is so limited.

    Do you have a reaction to this proposed change?

    Thanks,
    RWSenser
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-31 03:05
    The beauty of the cc1b compiler is that it has no builtin functions,
    so all functions that are available, are in libraries, and changeable.

    This also applies to the (membank) defines. Even though they are defined,
    you do not need to use them (or you can change the values). I find them handy,
    as membank0 represents the same memory area on sx18/20/28 and sx48/52,
    whereas·rambank 0 on the sx18/20/28 represents 0x10-0x1F, and on the sx48/52
    it represents 0x100-0x10F.
    It is arguable how I defined the values. Currently they represent physical
    memory layout, but you could redefine the sx18/20/28 to
    #define membank0 rambank -
    #define membank1 rambank 0
    #define membank2 rambank 1
    #define membank3 rambank 2
    #define membank4 rambank 3
    #define membank5 rambank 4
    #define membank6 rambank 5
    #define membank7 rambank 6
    #define membank8 rambank 7
    #define membank9 rambank -1
    #define membank10 rambank -1
    #define membank11 rambank -1
    #define membank12 rambank -1
    #define membank13 rambank -1
    #define membank14 rambank -1
    #define membank15 rambank -1
    #define membank16 rambank -1
    so it would appear sx18/20/28 have 9 banks of continues ram,
    which is actually not the case.

    Since strlen(char *s) is defined as published in many books, just add
    a new function strlenc(const char *s) or cstrlen(const char *s) to deal
    with constant strings. I prefer cstrlen().
    This actually applies to all functions that could have parameters from both ram
    and rom. There must be seperate functions, or you must use 16bit pointers
    which can be used for both ram and rom, but that increases codesize.
    Note that since strings in rom can be longer than 256 bytes, the cstrlen()
    must return a long int (16bits)
    long cstrlen(const char *s);

    Edit: something to check out.
    On page 28 of the cc5x manual it says
    The implementation of constant data supports the following features:
    • both 8 and 16 bit pointers to const data in the same application
    • the size of single const pointers can be chosen automatically
    const pointers can access both RAM and program memory
    • the compiler will not put all constant data in a single table, but rather make smaller tables if this
    saves code space

    On page 30 there are examples
    String parameters:
    myfunc("Hello"); // void myfunc(const char *str);
    myfunc(&tab[noparse][[/noparse]i]); // char tab[noparse][[/noparse]20]; // string in RAM
    myfunc(ctab); // const char ctab[noparse]/noparse = "A string";

    From this example I understand const char *str accepts both ram and rom addresses.
    It isn't mentioned explicitly, but I suspect ram pointers (8bit) are converted to 16bit to support
    both ram and rom. If you check out the generated code you'll see that strings are stored
    as retw tables. I think if we come up with some function that uses IREAD we can do better
    than the code generated by cc1b.

    regards peter


    Post Edited (Peter Verkaik) : 7/31/2007 6:26:23 PM GMT
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-07-31 18:23
    The use of const char * parameters in functions, makes cc1b insert small pieces of
    runtimecode. I think there is one piece per const * parameter.
    _const1
    ······· MOV·· ci,W
    ······· MOV·· W,ci
    ······· AND·· W,#1
    ······· ADD·· PCL,W
    ······· RETW· 0
    ······· RETW· 0
    _const2

    My library cstring.h has 9 functions, each of which has 1 const char * parameter,
    and then 9 pieces of runtime code are inserted.

    To overcome this I wrote a library dstring.h (the d in dstring stands for data - from cdata)
    that uses long instead of const char *.
    #pragma cdata must then be used to store strings in rom.
    Example:
    //area for storage of constant data (at end of program code)
    #define CDATA_START (_CHIP_CODESIZE_ - 0x0100)
    #pragma cdata[noparse][[/noparse]CDATA_START]
    #pragma cdata.LabelName = "Hello world\0"
    #pragma cdata.AnotherLabel = "Direct storage\0"
    #pragma cdata.Numbers = 0xF00,0xABC,0x0F
    #pragma cdata.LabelTable = LabelName,AnotherLabel,Numbers
    #pragma cdata.CDATA_END

    The define _CHIP_CODESIZE_ has been added to the chip header files.
    To get the length of a string in rom you can use
    long p = dstrlen(LabelName);
    I added 2 functions to memory.h
    long RomWord(long addr); //get word (12bits) from rom address
    char RomChar(long addr); //get char (8bits) from rom address
    I have put the const char * functions now in their own cstring.h library.
    (the c in cstring stands for const - from const *)
    The file memory_test.c shows a general program layout, including cdata.

    regards peter

    Post Edited (Peter Verkaik) : 7/31/2007 7:29:30 PM GMT
Sign In or Register to comment.