Shop OBEX P1 Docs P2 Docs Learn Events
C4SX: Update a next release — Parallax Forums

C4SX: Update a next release

RW SenserRW Senser Posts: 61
edited 2007-08-09 15:05 in General Discussion
If you are interested in the C4SX C compiler, this status update might be of interest to you:

While testing the C4SX utilities and·libraries,·and CC1B compiler for this next C4SX release I found what looks like a bug in the CC1B handling of C 'static const char' fields when these fields are accessed via 16-bit pointers.· How is that for a mouth full??··· Seriously, this is important for the SXIO.H, string.h and other libraries that I would like to add to C4SX.

So, while I sort this out there will be a delay in the next release of C4SX.· I have not seen this bug impact C data types other than 'static const char'.· So, CC1B is still very usable.

Sorry for the delay,
RWSenser

Comments

  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-08-02 00:59
    Do you have an example of this bug?
    regards peter
  • RW SenserRW Senser Posts: 61
    edited 2007-08-02 13:41
    file: bug1detail.txt
    08/02/2007

    Hi Peter,

    This SX-28 bugs hits when the 16-bit pointers are in RAM pages 4-7, when a function is
    being called with a 'static const char' parameter.· When I move the pointer to a
    lower RAM page, no error.· Here are some code snippets:

    Called function:
    int puts(const char *in_str)
    {
    ··· while (*in_str != 0) {
    ······· putchar(*in_str);
    ······· in_str++;
    ··· }
    ··· return(0);
    }

    variable( passed argument)·of interest:
    static const char msg[noparse][[/noparse]12] = "marker msg!";

    calling code:
    // #if 0 -- c1.7 try split
    ·puts(msg); // c 1.8

    Line from 'var' file:
    ·L· 7· 0x0F0····· 2· : 22:· in_str
    note the '7'

    Generated code for call:
    ······················· ;·puts(msg); // c 1.8
    ······· BANK· 224
    ······· CLRB· 4.FSR_7
    ······· CLR·· in_str
    ······· MOV·· W,#128
    ······· MOV·· in_str+1,W
    ······· CALL· puts

    Generated code for function entrance:
    ·· 610········································· ;
    ·· 611········································· ;int puts(const char *in_str)
    ·· 612········································· ;{
    ·· 613········································· ;··· while (*in_str != 0) {
    ·· 614· 010C· 001F····· m018··· BANK· 224
    ·· 615· 010D· 04E4············· CLRB· 4.FSR_7
    ·· 616· 010E· 0210············· MOV·· W,in_str
    ·· 617· 010F· 0019············· BANK· 32
    ·· 618· 0110· 0033············· MOV·· ci,W
    ·· 619· 0111· 001F············· BANK· 224
    ·· 620· 0112· 0211············· MOV·· W,in_str+1
    ·· 621· 0113· 0019············· BANK· 32
    ·· 622· 0114· 0034············· MOV·· ci+1,W
    ·· 623· 0115· 0935············· CALL· _const1
    ·· 624· 0116· 0F00············· XOR·· W,#0
    ·· 625· 0117· 0643············· SNB·· 3.Zero_
    ·· 626· 0118· 0B2D············· JMP·· m019

    Analysis:
    1)· Likely bug, notice the the CLRB· 4.FSR_7 is forcing the use of a bank other than 7,
    ··· the var file shows that·7 is intended.
    2)· More major bug, notice that the passed bytes are addressed by
    ·BANK 224
    ·CLRB 4.FSR_7
    ···· But the code to retrieve the bytes that make up the 16-bit pointer is using
    ······· BANK 224
    ······· CLR· 4.FSR_7
    ···· only for the first byte, and then the second is just
    ······· BANK 224
    ···· -- OR -- said again:
    notice that the first byte of in_str gets
    BANK 224
    CLRB· 4.FSR_7
    MOV·· W,in_str
    but the second only gets
    BANK· 224
    MOV·· W,in_str+1

    I suspect this bug is something from SX 48/52 support code.· As I remember, for the
    48/52 there is a need to set an FSR bit after a BANK instruction.

    I'm in the processing of writing this up to send the B. Knudsen.

    Thanks,
    RWSenser
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-08-02 13:54
    So you get this error when you have
    static const char pp[noparse]/noparse = "hello world\n\0";
    and you·call a function
    puts(pp);

    Do you also get the error when you use
    const char pp[noparse]/noparse = "hello world\n\0";

    The use of static for a constant array is pointless imho.
    You would use static for a pointer though:
    static const char *mypointer;
    but then mypointer is a ram variable

    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-08-02 14:09
    It looks to me the
    CLRB 4.FSR_7
    must be
    SETB 4.FSR_4·· ->bank 224 ($E0) followed by SETB 4.FSR_4 sets fsr to $F0
    because on the sx18/20/28 only the odd rambanks are available. (why not bank 240 directly?)
    If you change the necessary statements in your .src file
    does your program then run without error?

    From sx manual:
    Often it is desirable to set the bank select bits of the FSR with one instruction cycle (the MOV FSR,
    #literal commands above take two cycles). The SX instruction set offers such an instruction called Bank.
    The Bank instruction sets the upper bits of the FSR to point to the RAM bank required. Note: On the
    SX48/52, the BANK instruction only selects one of 8 banks in either the lower 8 or upper 8 banks. FSR.7 selects
    the lower or upper group of 8 banks. To select a bank, use MOV FSR, #literal or add an SETB FSR.7 instruction
    after the BANK instruction.

    regards peter


    Post Edited (Peter Verkaik) : 8/2/2007 2:19:55 PM GMT
  • RW SenserRW Senser Posts: 61
    edited 2007-08-02 16:09
    Hi Peter,

    I tried your suggestion above with removal of the 'static', CC1B does not 'like' this construct:

    // peter test, remove static
    /* static */ const char msg[noparse][[/noparse]12] = "marker msg!";
    ^
    Error sxstring.c 97: Limitation: 'static const' is needed.

    I tried a similar thing to what you suggested above (removal of the CLRB instruction); this patch to the asm code fixes the error.

    I've sent a description of this problem to bknd.com. It's very likely I'll get a timely reply.

    Thanks for the info,
    RW Senser
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-08-02 16:42
    I don't know why your compiler complains about static!
    The following code compiles fine at my pc (for sx28).

    page3 const char pp[noparse]/noparse = "hello world\n\0";
    const char *q @0xF0;

    void puts(const char *s) {
    · if (*s) {
    ··· s++;
    · }
    }

    void main(void) {
    · const char *p = pp;
    · puts(pp);
    · puts(p);
    · q = pp;
    · while (1) {
    · }
    }

    and here is the asm for main
    main
    ······················· ;//· char i; long q;
    ······················· ;· const char *p = pp;
    ······· BANK· 64
    ······· CLRB· 4.FSR_7
    ······· CLR·· p
    ······················· ;· puts(pp);
    ······· CLR·· s_25
    ······· CALL· puts
    ······················· ;· puts(p);
    ······· MOV·· W,p
    ······· MOV·· s_25,W
    ······· CALL· puts
    ······················· ;· q = pp;
    ······· BANK· 224
    ······· CLR·· q
    ······················· ;· while (1) {
    ······················· ;· }
    m001··· JMP·· m001

    I checked it with sxsim and it works.
    bank 224 sets ram selection to $F0-$FF according to sxsim.

    Here is a macro from an asm source of mine
    ·;*********************************************************************************
    ·; Macro: _bank
    ·; Sets the bank appropriately for all revisions of SX.
    ·;
    ·; This is required since the bank instruction has only a 3-bit operand, it cannot
    ·; be used to access all 16 banks of the SX48/52. For this reason FSR.4 (for SX48/52BD/ES)
    ·; or FSR.7 (SX48/52bd production release) needs to be set appropriately, depending
    ·; on the bank address being accessed. This macro fixes this.
    ·;
    ·; So, instead of using the bank instruction to switch between banks, use _bank instead.
    ·;
    ·;*********************************************************************************
    _bank·macro·1
    ·bank·\1
    ·ifdef DEV48
    ··if \1 & %10000000··;SX48BD and SX52BD (production release) bank instruction
    ···setb·fsr.7··;modifies FSR bits 4,5 and 6. FSR.7 needs to be set by software.
    ··else
    ···clrb·fsr.7
    ··endif
    ·endif
    ·endm

    However, I recall fsr.4 had to be set all the time for sx18/20/28.
    Has that changed too and is it internally sticked to 1 ???
    (224 is $E0 so b4 is cleared. and rambank $E0-$EF is not available on sx18/20/28)

    Edit: I got the answer to my own question:
    In direct addressing bit4-bit0 of the fsr is not used (sx18/20/28).
    Full explanation on pages 156-159 of the sxkey manual.
    So the fix to the bug is the removal of CLRB 4.FSR_7 as RW Senser tested.

    regards peter

    Post Edited (Peter Verkaik) : 8/2/2007 8:16:07 PM GMT
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-08-02 16:51
    I just found out that if you place
    page3 const char pp[noparse]/noparse = "hello world\n\0";
    inside main() or other function,
    then the compiler complains about static.
    So if you move the const declaration outside the function
    then the static is not required.

    regards peter
  • RW SenserRW Senser Posts: 61
    edited 2007-08-06 04:09
    Hi Peter (and anyone else interested in C4SX),

    Greetings.

    Attached is a zip file with a test program called sxstring.h that uses the stdlib.h, sxio.h·and other libraries.· I have put a small change into sxio.h that arranges the variables in memory such that the bug I found with 'static const char ...' ·is not present.· I've included the·sxio-x.h, which fails (if you want to see the coding·difference).

    If you have time, could you download this zip and run the sxstring.h on your SX 28?· Note that I have changed some of the string.h, stdlib.h, etc. libraries -- and sxstring.c needs these changed versions. If you have a serial I/O capability great; if not run the program under the debugger and you can see the test results in the RAM/registers.

    I'm interested in knowing the results you get for the 8 tests -- and if any corruption or odd errors occur.

    I've not yet heard back from the CC1B people.· In any event, the compiler bug is rather obscure and I think I can describe how to avoid it·well enough that C coders can work around the issue.

    Thanks,
    RWSenser
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-08-06 15:41
    RW Senser,

    I downloaded your files and tried to compile with my existing libraries.
    As you specified you need slightly different functions. Changing existing
    library functions is not the way. Just make a new function with a parameter
    list that suits your·needs, in this case with const char * parameters.
    These functions are available in cstring.h

    To compare two string in ram, use strcmp().
    To compare a string in ram with a constant string, use cstrcmp().
    I·included <cstring.h> in your sxstring.c and now it compiles without
    changing the string.h functions.

    I did get a few compile errors that cc1b was unable to update bank register bits.
    This always occured on expressions like
    *s++ = temp;
    where temp is a local variable.
    The problem is that *s uses indf to write a value, which must either be in the
    same bank as the value, or the value must be stored in mapped ram (global ram 0x00-0x0F).
    For some functions I therefor defined locally
    shadowDef char gTemp @0x0A;
    char save = gTemp; //save mapped ram
    //perform function
    gTemp = save; //restore mapped ram
    return result;
    This means of course that those library functions cannot be used
    with parameters stored in mapped ram @0x0A because that location
    is used·to perform the function.

    In my opinion no library should use mapped ram for permanent storage.
    I noticed your SXIO.H uses one byte in the mapped ram for flags.
    It also uses #pragma rambank 0
    Be aware that if·you use that library on·a sx48, the coding and therefor
    timing will be different, because ram bank 0 on a sx48·uses semi-direct
    addressing. If you use #pragma membank1 then ram addresses 0x10-0x1F
    are used on both sx28 and sx48.

    I am currently busy figuring out how I can add global variables to a library
    (like your rambank 0 variables in your sxio.h) without actually placing them
    on a specific location, because that limits the use of a library.
    I have some test files running that are based on my assembly Virtual Peripheral library
    (which uses sasm macros to include and locate only code that is required,
    much like the cc1b libraries) but it needs to be more tuned to·C, rather than assembly.

    If you download the libraries to your cc1b folder,
    you can compile the attached sxstring.c

    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-08-08 17:52
    I wrote a cc1b macro to deal with global variables in libraries.
    This macro issues a #pragma membank? whenever a declared
    variable does not fit in the current rambank.
    These macros are in memory28.h (for sx18/20/28) and memory48.h
    (for sx48/52). These files are automatically included in memory.h

    Suppose you want to declare a global variable inside a library
    char myGlobal[noparse][[/noparse]5];
    with the macro you can simply do
    DeclareGlobalVar(char myGlobal[noparse][[/noparse]5],5)
    so you pass the declaration and the number of bytes the variable occupies.
    The macro checks if it fits in the current rambank. If not, the variable
    is moved to the next rambank.

    There is a second macro named membankUpdate that takes no arguments
    and simply moves to the next rambank.
    You would use that macro in your main C file when cc1b issues an error there are
    too few ramlocations, or in a library if you declare more than 16 bytes of variables.
    For example in a main C file:
    #include <memory.h>
    membankUpdate
    #define VP_SLOTS 6
    #include <vpdef.h>
    //membankUpdate
    #include <vplib.h>
    //membankUpdate
    #define VP_DEFS 7

    It appears to work, the only manual involvement is to add an occasional membankUpdate.
    Using DeclareGlobalVar() inside libraries should make it possible to leave out #pragma membank?
    statements inside the libraries, meaning libraries can be included in any order without conflict.

    There are some issues I came accross.
    I used to define
    shadowDef char gTemp @0x0A;
    char save = gTemp;
    //perform function
    gTemp = save;
    return result;

    This saving and restoring of gTemp inside a function takes alot of code and occurs frequently.
    It turns out it is better to declare a global ram variable permanently that can
    be used as a placeholder. Since location 0x0F is already used by cc1b for
    temporary storage, I declared
    char _SystemTemp @0x0E;
    in memory.h
    Whenever a global ram location is required, _SystemTemp can serve that purpose.
    Just remember its contents may be lost when calling a function, so its best use is:
    _SystemTemp = somefunction(); //get a value
    *s++ = _SystemTemp; //store that value
    //at this point _SystemTemp can be used for other purposes

    I added a function RomCopy(char dest, long source, char len)
    to memory.h
    This copies bytes from rom to ram.
    Here I discovered a cc1b bug.

    void RomCopy(char dest, long source, char len) {
    · char i = 0;
    · while (len > 0) {
    ··· _SystemTemp = RomChar(source);
    ·char k = LargeArrayAddress(dest,i);
    ·_SystemRam[noparse][[/noparse]k] = _SystemTemp;
    /*<?asm
    ·bank source ;;cc1b misses this statement
    ?>*/
    ·source++;
    ·i++;
    ·len--;
    · }
    }

    cc1b misses a bank statement after writing a value using indf.
    I fixed it by adding the bank statement. Note that it only works
    while there is no other local parameter named source (otherwise cc1b
    may rename source to source_1)

    The test program vp_test.c is a first setup to find an easy·way to include multiple
    Virtual Peripherals. It should be possible to dynamically install and remove VP's.
    I am not quite happy about the handle (uartrx in main()) as that requires storage.
    Possibly we can do without the handle if the defined VP's can only be installed once,
    while allowing the same VP type to be installed more than once.

    The big issue here however are the macros, so we won't need to specify
    any specific ramlocation for global variables in libraries.
    If anyone finds something not working about those macros, please report.

    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2007-08-09 15:05
    The macros are not the solution. Whenever some ram locations are skipped to move
    to the next rambank, those skipped locations are not being used by the compiler.
    So I read the cc5x manual again to come up with a better approach.

    #pragma mainStack 3 @ 0x20 // set lower main stack address

    Using this pragma means that local variables, parameters and temporary variables of size 3 bytes and
    larger (including tables and structures) will be stored in a single stack allocated no lower than address
    0x20. Smaller variables and variables with a bank modifier will be stored according to the default/other
    rules. Using size 0 means all variables including bit variables.


    So if we put
    #pragma mainStack 0 @0xF0
    at the start of our main C file, then all local parameters are allocated from 0xF0 upwards. (manual page 20)

    Priority when allocating variables:
    1. Variables permanently assigned to a location
    2. Local variables allocated by the compiler
    3. Global variables allocated by the compiler
    If we define global variables at a specific location then the variable is placed at that location (highest priority, manual page 13),
    but that location may be a defined constant. So if we demand that certain constants must be defined
    before a library is included, then the library global variables can be manipulated from the main C file. That at least
    prevents the need·to alter libraries due to memory conflicts.
    I have the files vpdef.h and vplib.h now setup in this way. If the required constants are not defined, the library throws an error.
    For example, vpdef.h requires two constants to be defined.
    At the·beginning of the library file I placed two·tests:

    #ifndef _VPDEF_H_VPSLOTS
    #error _VPDEF_H_VPSLOTS must be defined before including <vpdef.h>
    #else
    #if (_VPDEF_H_VPSLOTS < 1) || (_VPDEF_H_VPSLOTS > 8)
    #error _VPDEF_H_VPSLOTS must be in the range 1..8
    #endif
    #endif
    #ifndef _VPDEF_H_vpData0
    #error _VPDEF_H_vpData0 must be defined before including <vpdef.h>
    #else
    #if (_VPDEF_H_vpData0 < 0x10) || ((_VPDEF_H_vpData0 & 0x0F) != 0)
    #error _VPDEF_H_vpData0 must start at rambank begin
    #endif
    #endif
    Although this is a bit more work for the libraries, it does make sure the constants are defined properly
    and it allows us to change the memory map from a single place, the main C file.
    Note that·the library constants that must be defined, have a nameprefix identical to the library name.
    This is not required (any name can be used) but ensures the names are·unique (which they must).

    regards peter

Sign In or Register to comment.