FTDI Community

Please login or register.

Login with username, password and session length.
Advanced Search  

News:

Welcome to the FTDI Community!

Please read our Welcome Note

Technical Support enquires
please contact the team
@ FTDI Support


New Bridgetek Community is now open

Please note that we have created the Bridgetek Community to discuss all Bridgetek products e.g. EVE, MCU.

Please follow this link and create a new user account to get started.

Bridgetek Community

Author Topic: Vinculum II Toolchain (VinC) Issues Porting Code  (Read 9716 times)

KTrenholm

  • Newbie
  • *
  • Posts: 12
    • View Profile
Vinculum II Toolchain (VinC) Issues Porting Code
« on: October 18, 2021, 04:49:15 PM »

Hey all,

I'm working on a project to turn the VNC2 into essentially a bootloader host for a Cypress PSoC5LP.  The idea being to connect a USB flash drive to the system, read the firmware file, and bootload the MCU via the UART.

This would in theory not be too much trouble, as Cypress actually provides the C (I think GCC) code for a bootloader host for use in this exact kind of situation.  I figured porting the bootloader host wouldn't be too tall of an order.  However I am running into problems with VinC throwing some unexpected syntax errors.

First thing I noticed what was that the toolchain appears to have no stdint.h?  Since all the bootloader host code is written with standard types like uint8_t/uint16_t/uint32_t I just needed a few typedefs.  I included my own header file to provide the needed types and replaced the includes of stdint.h with my own little "int.h":

Code: [Select]
#ifndef _INT_H_
#define _INT_H_

typedef signed char int8_t;
typedef signed short int16_t;
typedef signed long int32_t;

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;

#endif

No problems so far, I get a few warnings for mismatched widths/signs on certain calls but I can resolve those easily enough.
The real weirdness starts with the C1000 errors I'm getting:
..\cybootloaderutils\cybtldr_api.c line 401: (error) C1000 syntax error, unexpected TYPE_NAME
..\cybootloaderutils\cybtldr_api.c line 423: (error) C1000 syntax error, unexpected TYPE_NAME
..\cybootloaderutils\cybtldr_api.c line 456: (error) C1000 syntax error, unexpected TYPE_NAME


I'm not sure where these are cropping up from.  Here's the function with the call that causes the first C1000 error:
Code: [Select]
int CyBtldr_ProgramRow_v1(uint32_t address, uint8_t* buf, uint16_t size)
{
    const int TRANSFER_HEADER_SIZE = 15;

    uint8_t inBuf[MAX_COMMAND_SIZE];
    uint8_t outBuf[MAX_COMMAND_SIZE];
    uint32_t inSize;
    uint32_t outSize;
    uint16_t offset = 0;
    uint16_t subBufSize;
    uint8_t status = CYRET_SUCCESS;
    int err = CYRET_SUCCESS;

    uint32_t chksum = CyBtldr_ComputeChecksum32bit(buf, size);

    if (CYRET_SUCCESS == err)
        err = SendData(buf, size, &offset, (uint16_t)(g_comm->MaxTransferSize - TRANSFER_HEADER_SIZE), inBuf, outBuf);

    if (CYRET_SUCCESS == err)
    {
        subBufSize = (uint16_t)(size - offset);

        err = CyBtldr_CreateProgramDataCmd(address, chksum, &buf[offset], subBufSize, inBuf, &inSize, &outSize);    //401 - C1000 syntax error: unexpected TYPE NAME
        if (CYRET_SUCCESS == err)
            err = CyBtldr_TransferData(inBuf, inSize, outBuf, outSize);
        if (CYRET_SUCCESS == err)
            err = CyBtldr_ParseDefaultCmdResult(outBuf, outSize, &status);
        if (CYRET_SUCCESS != status)
            err = status | CYRET_ERR_BTLDR_MASK;
    }

    return err;
}

The code for the function in question is here:
Code: [Select]
int CyBtldr_CreateProgramDataCmd(uint32_t address, uint32_t chksum, uint8_t* buf, uint16_t size, uint8_t* cmdBuf, uint32_t* cmdSize, uint32_t* resSize)
{
    const uint16_t COMMAND_DATA_SIZE = 8;
    uint16_t i;
    *resSize = BASE_CMD_SIZE;
    *cmdSize = BASE_CMD_SIZE + COMMAND_DATA_SIZE + size;

    fillData32(cmdBuf + 4, address);
    fillData32(cmdBuf + 8, chksum);
    for (i = 0; i < size; i++)
        cmdBuf[i + 4 + COMMAND_DATA_SIZE] = buf[i];
    return  CreateCmd(cmdBuf, *cmdSize, CMD_PROGRAM_DATA);
}


I'm kind of at a loss as to where an unexpected TYPE_NAME could be coming up.  If it was an issue with my typedefs, I'd think this error would be cropping up in many more places.

Here are the other places this error is thrown:
Code: [Select]
int CyBtldr_EraseRow_v1(uint32_t address)
{
    uint8_t inBuf[MAX_COMMAND_SIZE];
    uint8_t outBuf[MAX_COMMAND_SIZE];
    uint32_t inSize = 0;
    uint32_t outSize = 0;
    uint8_t status = CYRET_SUCCESS;
    int err = CYRET_SUCCESS;

    if (CYRET_SUCCESS == err)
        err = CyBtldr_CreateEraseDataCmd(address, inBuf, &inSize, &outSize);    //423 - C1000 syntax error: unexpected TYPE NAME
    if (CYRET_SUCCESS == err)
        err = CyBtldr_TransferData(inBuf, inSize, outBuf, outSize);
    if (CYRET_SUCCESS == err)
        err = CyBtldr_ParseEraseRowCmdResult(outBuf, outSize, &status);
    if (CYRET_SUCCESS != status)
        err = status | CYRET_ERR_BTLDR_MASK;

    return err;
}


int CyBtldr_VerifyRow_v1(uint32_t address, uint8_t* buf, uint16_t size)
{
    const int TRANSFER_HEADER_SIZE = 15;

    uint8_t inBuf[MAX_COMMAND_SIZE];
    uint8_t outBuf[MAX_COMMAND_SIZE];
    uint32_t inSize;
    uint32_t outSize;
    uint16_t offset = 0;
    uint16_t subBufSize;
    uint8_t status = CYRET_SUCCESS;
    int err = CYRET_SUCCESS;

    uint32_t chksum = CyBtldr_ComputeChecksum32bit(buf, size);

    if (CYRET_SUCCESS == err)
        err = SendData(buf, size, &offset, (uint16_t)(g_comm->MaxTransferSize - TRANSFER_HEADER_SIZE), inBuf, outBuf);

    if (CYRET_SUCCESS == err)
    {
        subBufSize = (uint16_t)(size - offset);

        err = CyBtldr_CreateVerifyDataCmd(address, chksum, &buf[offset], subBufSize, inBuf, &inSize, &outSize);    //456 - C1000 syntax error: unexpected TYPE NAME
        if (CYRET_SUCCESS == err)
            err = CyBtldr_TransferData(inBuf, inSize, outBuf, outSize);
        if (CYRET_SUCCESS == err)
            err = CyBtldr_ParseDefaultCmdResult(outBuf, outSize, &status);
        if (CYRET_SUCCESS != status)
            err = status | CYRET_ERR_BTLDR_MASK;
    }

    return err;
}

Might anyone have an idea as to why this specific error is being thrown (or how to resolve it)?
Logged

FTDI Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 889
    • View Profile
Re: Vinculum II Toolchain (VinC) Issues Porting Code
« Reply #1 on: October 20, 2021, 04:59:52 PM »

Hello,

Please try renaming the variable from "address" to anything else.

Code: [Select]
typedef signed char                           int8_t;

int t2(int8_t address)
{
    return  0;
}

int t1()
{
                int8_t paramt1;

                t2(paramt1);    //401 - C1406
               
                return 0;
}

Both of these work:

int t2(int8_t badress)

int t2(int8_t baddress)

Best Regards,
FTDI Community
Logged

KTrenholm

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Vinculum II Toolchain (VinC) Issues Porting Code
« Reply #2 on: October 20, 2021, 06:01:08 PM »

Indeed, changed "address" to "addr" and it cleared it right up.  I would expect the editor in the IDE to color it like a type if it was reserved by the toolchain in some way.  Time to do a whole lot of find/replace, as you can imagine for a bootloader, the name address is everywhere.

I don't know if I would have ever considered the name "address" being the problem!
Thanks for the tip!

(P.S. There is no mention of "address" being a reserved word/type in AN151 - Vinculum-II User's Guide, at least not that I could find.  Worth noting this does not seem to be documented anywhere)

I also found something else weird.  VinC will not compile this CRC32 table:
Code: [Select]

    enum {
        g0 = 0x82F63B78,
        g1 = (g0 >> 1) & 0x7fffffff,
        g2 = (g0 >> 2) & 0x3fffffff,
        g3 = (g0 >> 3) & 0x1fffffff,
    };

    static const uint32_t table[16] =
    {
        0,                  (uint32_t)g3,           (uint32_t)g2,           (uint32_t)(g2^g3),
        (uint32_t)g1,       (uint32_t)(g1^g3),      (uint32_t)(g1^g2),      (uint32_t)(g1^g2^g3),
        (uint32_t)g0,       (uint32_t)(g0^g3),      (uint32_t)(g0^g2),      (uint32_t)(g0^g2^g3),
        (uint32_t)(g0^g1),  (uint32_t)(g0^g1^g3),   (uint32_t)(g0^g1^g2),   (uint32_t)(g0^g1^g2^g3),
    };

This throws (error) C2001 expression not constant for every element in that table that isn't 0 or g0.  All elements in the table should be calculable at compile-time (ARM-GCC and MSVC++ have no problems).  At the end of the day I can calculate these all out in another compiler or even just through a programmers calculator and put the constants into my VNC2 project.  Still, kind of a pain.

EDIT: found this in the Toolchain ReadMe, sounds like what I was running into:
Quote
Restrictions:
- Floating point not supported.
- Structs and unions may not be passed to or returned from a function. Pointers to structs and unions are allowed.
- Vacuous declarations of structures and unions is not supported.
- Structure and union assignments not supported.
- Anonymous aggregates, unnamed members in unions, are not supported.
- Compound literals expressions are not supported.
- Modulus operations treat signed values as unsigned values. Do not use with negative values.
I'd imagine those table entries are "Compound literal expressions"?
« Last Edit: October 21, 2021, 05:15:25 PM by KTrenholm »
Logged

KTrenholm

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Vinculum II Toolchain (VinC) Issues Porting Code
« Reply #3 on: October 21, 2021, 04:43:20 PM »

So here's a question regarding the stdio library.  I need to use fgets() which is noted in stdio.h as "To Be Added".  So let's put one in.  The fgets() implementation I'm using makes use of fgetc(), which is implemented in stdio.  However I can't find a reference for the EOF return value?  I need to check for EOF on the fgetc() call.  I know normally (in most implementations at least?) EOF == -1, but I'm not about to take that as gospel just because that's how it works in GCC, as the C standard says it can be implementation defined.  Would anyone be able to confirm what fgetc() returns when the end of file is encountered?  Is the FAT_EOF enum what I should be using?
[EDIT] I was able to rather than use the return value of fgetc() with any kind of EOF value use the feof() function to determine end of file and it seems to work

Oh, and a new bit of fun, I had to also put an implementation of strcspn() in, and the compiler does not much care for assigning pointers in the declaration:
Code: [Select]
static size_t strcspn(const char * s1, const char * s2){
    char *s = s1;    //Error C2808 illegal use of pointer
    char *c;

    while (*s1)
    {
        for (c = s2; *c; c++)
{
    if (*s1 == *c)
        break;
}

        if (*c)
    break;
s1++;
    }

    return s1 - s;

}

moving the assignment after the declaration clears it up:
Code: [Select]
static size_t strcspn(const char * s1, const char * s2){
    char *s;   
    char *c;

    *s = s1;    //No Errors Thrown!

    while (*s1)
    {
        for (c = s2; *c; c++)
        {
            if (*s1 == *c)
    break;
        }

        if (*c)
    break;
        s1++;
    }

    return s1 - s;

}
« Last Edit: October 21, 2021, 08:54:48 PM by KTrenholm »
Logged

FTDI Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 889
    • View Profile
Re: Vinculum II Toolchain (VinC) Issues Porting Code
« Reply #4 on: October 22, 2021, 05:03:55 PM »

Unfortunately the compiler doesn't do all constant initialisation which you might expect on other compilers.

If the values are expressed as constants without typecasting then it will compile.

   
Code: [Select]
enum {
        g0 = 0x82F63B78,
        g1 = (g0 >> 1) & 0x7fffffff,
        g2 = (g0 >> 2) & 0x3fffffff,
        g3 = (g0 >> 3) & 0x1fffffff,
    };
                               
    static const int table[16] =
    {
        0,                  g3,           g2,          (g2^g3),
     g1,       (g1^g3),      (g1^g2),      (g1^g2^g3),
        g0,       (g0^g3),      (g0^g2),      (g0^g2^g3),
        (g0^g1),  (g0^g1^g3),   (g0^g1^g2),   (g0^g1^g2^g3),
   };

I’ve not checked the values in the code though. They are precompiled (in decimal) to the following values according to the ASM output file:

0, 274646895, 549293790, 820201905, 1098587580, 1361435347, 1640403810, 1905808397, -2097792136, -1834419177, -1572096602, -1307217207, -1014159676, -741088853, -483350502, -210866315

Best Regards,
FTDI Community
Logged

KTrenholm

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Vinculum II Toolchain (VinC) Issues Porting Code
« Reply #5 on: October 22, 2021, 07:27:38 PM »

Interesting, good to know w/ regard to the casts.

I ended up just defining the table on a different microcontroller and snooped the values with the debugger tool.  Here's the table I ended up with in hex (looks to line up with your decimal equivalents):
Code: [Select]
static const uint32_t table[16] =
    {
        0,                    (uint32_t)0x105EC76F, (uint32_t)0x20BD8EDE, (uint32_t)0x30E349B1,
        (uint32_t)0x417B1DBC, (uint32_t)0x5125DAD3, (uint32_t)0x61C69362, (uint32_t)0x7198540D,
        (uint32_t)0x82F63B78, (uint32_t)0x92A8FC17, (uint32_t)0xA24BB5A6, (uint32_t)0xB21572C9,
        (uint32_t)0xC38D26C4, (uint32_t)0xD3D3E1AB, (uint32_t)0xE330A81A, (uint32_t)0xF36E6F75,
    };

Logged

FTDI Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 889
    • View Profile
Re: Vinculum II Toolchain (VinC) Issues Porting Code
« Reply #6 on: October 25, 2021, 05:03:11 PM »

Hello,

In reply to your previous questions:

Please try swapping the first two lines of the function around.

Code: [Select]
static size_t strcspn(const char * s1, const char * s2){
    char *c;
    char *s = s1; 
 

The readme file mentions that this might be a problem:

- At optimisation levels of 2 and above, if the first variable declaration in a function also initialises the variable then the initialisation may not occur. Separate the declaration and initialisation of the variable to workaround.

We only put the most basic implementation of the standard libraries that we could.

“A minimal set of C runtime library functions are provided” in the help file.
Further “NOTE: Not all the standard library functions have been included.”

We didn’t know fputc is there as it is not in the help file.

We will not be adding it into the standard libraries as it takes up space and reduces the amount of program space for other code.

We don’t claim to be compliant to any particular implementation of C.

Best Regards,
FTDI Community
Logged

KTrenholm

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Vinculum II Toolchain (VinC) Issues Porting Code
« Reply #7 on: October 27, 2021, 07:26:45 PM »

If it's OK I'm just going to drop another curiosity I came across here in hopes it might save others some time if they come across something similar.

This I found when transitioning my code over to Release from Debug.  Seems to occur when any kind of optimization level >0 is applied.  Works correctly on Level 0.

Consider the following implementation of fgets():
Code: [Select]
char * fgets(char *dst, int max, FILE *fp)
{
int c;
char *p;
int eof;

/* get max bytes or upto a newline */
for (p = dst, max--; max > 0; max--) {

c = fgetc(fp);

if ((eof = feof(fp)) != 0)
break;
*p++ = c;
if (c == '\n')
break;
}
*p = 0;

if (p == dst || eof != 0)
return NULL;
return (p);
}

What I found was with any optimization (any level >0) this would continue reading past the newline 0x0A character and continue until max is hit.
Changing the type of the c variable from:
Code: [Select]
int c;over to:
Code: [Select]
unsigned char c;solves the issue and it now the if statement works as intended and breaks on the newline character, but now I have an annoying warning that there is a return type mismatch on the fgetc() call, since according to the prototype in stdio.h, it returns an int.  To quiet that down, I tried going back to declaring c as an int, then casting c to uint8_t (unsigned char) for the if() statement:
Code: [Select]
if ((uint8_t)c == '\n')and this seems to work alright.  Must be something to do with how it tries to optimize the comparison between a int (signed 32-bit) and a signed or unsigned (I saw the same behavior when I used 0x0A instead of '\n') 8-bit literal.  My ASM is probably much too rusty to really dig through the compiled asm code to pinpoint it so I'll just leave it at that I suppose.



« Last Edit: October 27, 2021, 07:29:04 PM by KTrenholm »
Logged