Bugs and Gotchas

The Control-C cross-compiler was written by Fabius Software Systems and customized by Mosaic Industries to facilitate programming Mosaic embedded controllers in C. To program in C, use the IDE (Integrated Development Environment) based on the TextPad editor to create your source code program files. Clicking in the Terminal window and sending the download file to the 68HC11 microcontroller via the RS-232 serial link completes the process: you can then type main from your terminal to execute your program. This page summarizes known bugs.

Nested Arrays

When nesting arrays in C, like `values[sort[i]]`, fabius ignores the outer array and simply returns the value of the inner array. See the following example.

```int sort[5];
int values[5];

main( void )
{
int i;

sort[0] = 3;
sort[1] = 0;
sort[2] = 4;
sort[3] = 2;
sort[4] = 1;

values[0] = 42;
values[1] = 2034;
values[2] = 99;
values[3] = 12;
values[4] = 59;

printf("Values unsorted:" );

for( i = 0; i < 5; ++i )
{
printf( "%6d", values[i] );  // WORKS
}

printf("\nValues sorted:  ");
for( i = 0; i < 5; ++i )
{
printf( "%6d", values[ sort[i] ] );  // NOT WORKING
}

printf( "\nThe smallest number is %d.\n", values[ sort[0] ] ); // WORKS
}```

Nested Array Demonstration

The output should be:

```Values unsorted:    42  2034    99    12    59
Values sorted:      12    42    59    99  2034
The smallest number is 12.```

The actual output is:

```Values unsorted:    42  2034    99    12    59
Values sorted:       3     0     4     2     1
The smallest number is 12.```

Note that passing a constant in to a nested array is fine.

The solution is to use a temporary variable, like this:
```tmp = sort[i];
printf( "%d", values[tmp] );```

printf() and sprintf() floating point and fixed point notation display error

When using fixed point notation the function printf prints the minus sign for a negative number on the far left of the field while right justifying the rest of the number, inserting spaces between the minus sign and the number. Similarly, it doesn't right justify the minus sign on a floating point number when all of the width is not used, instead printing the minus sign on the far left.

For example,

`printf("\n%7.2f",-3.12);`

prints

`-  3.12`

`  -3.12`

We can work around this bug by first writing to a string and then correcting the string before printing it, as,

```char tempstring[16];

sprintf(tempstring,"%6.2f",-3.12);
if( tempstring[0] == '-' && tempstring[1] == ' ' )
{
*strrchr( tempstring, ' ' ) = '-';
tempstring[0] = ' ';
}

printf("%s",tempstring);```

printf() Floating Point Rounding Error

`printf()` appears to display a rounding error that depends on the number of places to the right of the decimal point specified in the command. It produces an error equal to one tenth of the value of the last decimal place. That is, if the number of places is `n`, the error is:

|error| = 10-(n+1)

For numbers whose absolute value is much greater than the least significant digit displayed the error is not important, but for numbers whose value is comparable the error can be profound.

Filenames Beginning with numbers

The Fabius C compiler cannot compile a .c file that begins with a number. There are no other restrictions, numbers are allowed as long as they aren't the first character. If a file does begin with a number you are likely to get a string of error messages, like this:

```WARNING: Duplicated symbol "_forth?ArrayFetch" (in
'C:\Mosaic\Fabius\Lib\qeddrvrs.o11' &
'C:\Mosaic\Fabius\Lib\qeddrvrs.o11') !
WARNING: Duplicated symbol "_forth?FArrayFetch" (in
'C:\Mosaic\Fabius\Lib\qeddrvrs.o11' &
'C:\Mosaic\Fabius\Lib\qeddrvrs.o11') !
WARNING: Duplicated symbol "_forth?ArrayStore" (in
'C:\Mosaic\Fabius\Lib\qeddrvrs.o11' &
'C:\Mosaic\Fabius\Lib\qeddrvrs.o11') !
...
...```

PORTA and ChangeBits

This note applies to the use of `PORTA, PORTB, PORTC, PORTD, PORTE` in conjunction with `ChangeBits(), ClearBits(), SetBits(), ToggleBits()`. If a port passed into one of these functions as the address paramater, it is logically correct to use an ampersand ( `&` ). This however causes a compiler error. The solution is to add to your code the following macros, based on the definitons in `c:/Mosaic/Fabius/Include/regs.h`, and pass them to the QED-Forth bit manipulation functions:

```#define PORTA_XADDR (REGISTER_BASE + 0x00uL)

You may also use C's built in bitwise operators with interrupts disabled or within an uninterruptible function. See this section for more information: create-your-own-uninterruptable-functions.

Duplicate XCONSTANT Definitions

In certain cases, the download file generated by the Mosaic IDE C compiler contains duplicate Forth definitions for the memory address of a variable, i.e.

``` DIN 009A47 XCONSTANT cond_cal
DIN 009A47 XCONSTANT cond_cal```

This will cause an error on download such as `COND_CAL isn't unique`. In this case, the executable file for the C compiler must be updated. Open the folder `C:\Mosaic\Fabius\Bin` and find Qcc.exe. Rename it to something like Qcc-bad.exe.

Copy Qcc.exe from this zip file into `C:\Mosaic\Fabius\Bin` in its place. You should now be able to compile your code for the QCard without duplicate XCONSTANT definitions appearing in the download file.

Initializing Structs and Unions

The Fabius compiler does not support C99 designated initializers for structs and unions, so it is necessary when initializing them to provide a value for each element in order, and specify a value for unions that matches its first element. For example:

```typedef union
{
float f;
struct {
unsigned known;
unsigned counts;
} p;
}
cond_pair_t;

typedef struct
{
cond_pair_t tare;
cond_pair_t midr;
cond_pair_t full;
}
cond_chan_nonvol_t;

#ifdef __GNUC__

const cond_chan_nonvol_t cond_nonvol_init_vals =
{
.tare = { .p = { .known = FL16_UNITY, .counts = TARE_COUNTS_DEFAULT } },
.midr = { .f = -UNITY              },
.full = { .f = -SENS_IMPED_DEFAULT }
};

#else   // fABIUS

// The float literal here is in memory 0x3c00e000, to initialize .tare
// with the pair { .known = FL16_UNITY, .counts = TARE_COUNTS_DEFAULT }.
const cond_chan_nonvol_t cond_nonvol_init_vals = { 0.007865906f, -UNITY, -SENS_IMPED_DEFAULT };

#endif   // ifdef __GNUC__ / fABIUS```

Struct/Union Initialization Example

Limited Input Domain For Bit Shift Operations

In some cases, an "Internal Compiler Error" will be produced on a bit shift operation, and the solution is to perform two smaller shifts instead:

```#ifdef __GNUC__
mant =  f32 >> 13;
#else  // fABIUS
mant =  f32 >> 7;
mant = mant >> 6;
#endif```

Floating Point Literals Truncated Rather Than Rounded

In compiling test code that checks for a specific floating point output value on both GCC and Fabius, you may encounter this issue. For floating point literals (specified in decimal), GCC rounds the literal to the closest binary floating point number. Fabius truncates the literal to the binary floating point number closer to zero. This can generally be resolved by adding extra digits to the literal or changing the last digit. For instance, `3.0517578e-5f` will be interpreted differently by GCC and Fabius, but `3.0517579e-5f` produces the same 32-bit value in both compilers. Similarly, `-1.5f` is interpreted differently in GCC and Fabius, but `-1.50000001f` is interpreted the same by both compilers.

No 32-bit Single-Precision Floating Point Transcendental Functions

All floating point functions accept and return 64-bit double-precision values in Fabius. Thus if you wish to compile code for both GCC, which has `math.h` functions with the `f` suffix indicating single-precision floating point, and Fabius, you will need to define macros for the 64-bit versions in Fabius:

```#ifndef __GNUC__
#define sqrtf(X) ((float)sqrt(X))
#define  logf(X) ((float)log(X))
#endif```

floor() and ceil() are O(n)

The `floor()` and `ceil()` functions in Fabius have an execution time proportional to the magnitude of their arguments for numbers of absolute value greater than 1. The larger the number, the longer these functions take to return a vlaue. At worst, with an argument of 216-epsilon these functions take 30 seconds to return 216-1 or 216 respectively.

You can avoid this problem by using the implementation of `truncf()` contained in this zip file. You must `#include "truncf.c"` in one of your source files, and `#include "truncf.h"` in every source file that needs to use it. Unlike `floor()` or `ceil()`, `truncf()` will truncate a number toward zero, reducing its absolute value if it is changed.

Warning on QED Forth functions returning 8-bit values

The underlying QED Forth operating system does not have a data type smaller than 16 bits, and the Fabius compiler's interface with QED-Forth has a bug in which even if the C wrapper functions around QED-Forth system functions like `AD8Sample()` are defined as `uchar`, the compiler treats the function as returning a 16-bit `uint` instead. This causes a warning about discarding significant bits when assigning the result to a variable of type `uchar`.

The workaround is to explicitly cast the result of QED-Forth system calls that return 8-bit values to either `char` or `uchar`. This can be done using the convention of all-capitals macro defined in a header file or at the top of any source files that need to use the relevant function.

```// Suppresses warning about discarding upper byte of
// return value from QED-Forth system function.

Handheld Demo Custom Font Error

The demo code previously distributed with the Handheld (Legacy) contains incorrect initialization of textboxes in the custom font screen. `textboxCustomFont` fails to set the TEXTBOX_FONT property before setting the size of the textbox as specified in textbox-object, and `textboxRegularFont` also attempts to set a custom font, when it is intended to use the default font. Lines 337 to 347 should be changed as follows:

```  textboxCustomFont = New_Object(TEXTBOX);
// TEXTBOX_FONT must be set before height and width.
Set_Property(textboxCustomFont, TEXTBOX_FONT, (long) fontComicSans);
Set_Property(textboxCustomFont, HEIGHT_IN_PIXELS, (long) 62);
Set_Property(textboxCustomFont, WIDTH_IN_PIXELS,  (long) 128);
STRING_TO_TEXTBOX(textboxCustomFont,"This is an example of Comic Sans 8 point font. Press the Menu key to exit.");

textboxRegularFont = New_Object(TEXTBOX);
Set_Property(textboxRegularFont, HEIGHT_IN_PIXELS, (long) 40);
Set_Property(textboxRegularFont, WIDTH_IN_PIXELS,  (long) 128);
STRING_TO_TEXTBOX(textboxRegularFont,"This is a second textbox written with the default font.");```

"String must be enclosed in double quotes"

```ERROR:   String must be enclosed in double quotes ! (file MAIN.A11 line 828)
ERROR:   Illegal initial character for label ! (file MAIN.A11 line 829)```

This error appears when a string literal exceeds 240 characters. Note that for the purposes of this limit, escape characters such as `\n` and `\t` count as two characters in the string literal. Note also that for concatenated strings such as the following, the limit applies to the total number of characters in the concatenated string:

```printf( "\nEnter the module number of the Motor Control Wildcard\n"
"( With J1 and J2 *not* installed, the module number is 0\n"
"  if the Wildcard is installed on top of a QCard." );```

The compiler will successfully copy the string literal into the .A11 assembly file, but the assembler will only process the first 240 characters of the string literal, resulting in the two errors above.

This page is about: Known Bugs, IDE Integrated Development Environment – Lists known bugs in the IDE integrated development environment.