TI's Code Composer does not clear bss data

You need to enable the appropriate warnings (I can't remember the exact flag off-hand - but it is included in "-Wall -Wextra").

Reply to
David Brown
Loading thread data ...

I don't see it that way. In fact, I strongly disagree.

I expect my tools to perform basically according to specifications. I can understand a certain amount of deviation from standards in certain areas, or inconvenient limitations, and I can cope with their being bugs in obscure or complicated features. But I will not willingly waste my time and effort writing code in a way that it will still work with a fundamentally broken tool. That is a waste of my time and my customers' money, and cannot possibly work anyway.

This CCS flaw seems to be peculiar to CCS - maybe another compiler has an equally fundamental and equally inconvenient flaw. Supposing for example that Microchip's compiler is unable to generate correct code for nested switches. Does that mean I should never use nested switches, in case I want to compile the code for a Microchip processor? No, it means that I will not choose to use Microchip's flawed compiler - if I am using those devices, I will use a different compiler for them. And if there are no alternative compilers, I will prefer not to use the chip. And if I have to use that chip and that compiler, then it will cost the customer extra for the extra time it takes to work around the flaw. But I won't pass on that cost to other customers.

For a concrete example of such a fundamental flaw in the tools, I have a compiler that I used on a particular target some 15 years ago. The flaw is partly the fault of the compiler, and partly the fault of the board arrangement, but the result is that this 16-bit processor can only access main ram as 8-bit - if the compiler generates 16-bit load or store instructions to main memory, half the data is lost. Data on the stack can be 16-bit without problems. This is clearly a major flaw, and takes a lot of effort to work around. But although I rarely use these tools, I will in fact be using them again sometime in the very near future. So should I make sure that the code I write for other projects uses the same workarounds, just so that I can share that code?

Most of the work I do is compiled using modern gcc versions, for different target processors. But sometimes I have to use older or more limited compilers. Should I go back to old-fashioned #define's for all my constants and macro functions, rather than using type-safe "static const" and "static inline" alternatives, just because of the limitations of other tools? Should I avoid using gcc's "typeof" operator even when if makes the code clearer and safer? Sometimes I write code that I know will have to work on a range of tools, but mostly I write code to make the best use of the tools I have, with the assumption that future tools will be at least as good.

Appnote code and example code is a different matter, and is (I hope!) written by different people than compilers and their libraries. Appnote code and examples are written to give you an idea of how it is possible to use a certain feature of the device - it should be clear and easy to follow, but it only needs basic functionality and doesn't need to be optimal, and often isn't heavily tested. Of course, it often isn't clear - but that's just bad examples.

Compiler code and low-level libraries need to be correct and well-tested, and preferably small and fast. Clarity of code is low down on the priority list (except so that the developers know that it is correct).

Reply to
David Brown

As I mentioned in another post, I thought I had seen compilers in the past warning about static variables not been explicitly assigned to before use.

In addition to doing this as well, I also go one further and declare all my integers as unsigned unless I actually need to store signed data into them.

However, I still cannot get over your toolkit vendor spending more time writing a note about not clearing .bss instead of actually just doing it.

I wonder if someone forgot to do it and your vendor wrote up a note afterwards justifying it's current behaviour rather than admitting they made a embarrassing mistake and just fixing the problem in the first place. :-)

Seriously however, it would be interesting to know why they do this.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world
Reply to
Simon Clubley

Interesting and I had not considered this.

[snip other equally interesting comments]

Thank you for spending the time writing a detailed writeup and covering issues I had not considered.

As I have mentioned in the past, I am a professional programmer, but a hobbyist when it comes to electronics work, so issues like this are ones I am not likely to encounter and hence don't consider unless made aware of them.

Thanks,

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world
Reply to
Simon Clubley

A lot of people who are used to microcontrollers think of jtag as just an interface for programming and debugging microcontrollers. But in fact it is designed as a board test interface, and a jtag bus is fundamentally a huge shift register. Different devices such as memory chips, processors, fpgas, etc., are all attached to the bus in serial. Then jtag commands are clocked along the bus. Initially, you use commands that are designed to identify the devices and you have commands to put different devices in active or passive states. Then when you have picked one (or more) devices to communicate with, you clock data into their test registers and read out the results of the last test.

Early jtag-based debug interfaces used precisely this method, with all the relevant debug registers attached in the chain. But if that is, for example, 10 registers with 32 bits each, then you need to clock in 320 (plus more for the command) bits even if you just want to set a single register, and you then need to clock through another 320 (plus command) bits to read the results.

This very quickly gets extremely slow, and you need intelligent debugger interface hardware (rather than a simple USB-to-spi converter, or PC parallel port interface as used to be common). So chip designers started cheating - they added new commands to the jtag interface that are not covered by any standard (though they are allowed and ignored by other devices), to allow more efficient communication.

Reply to
David Brown

On some small micros, unsigned comparisons are smaller and faster than signed comparisons - so unsigned helps here. It can make an even bigger difference with multiplication and division. But what is more important, is to ensure the sizes of your data are correct. Use #include , and use types like uint16_t and int8_t instead of plain "int". (For 8-bit processors, using int8_t and uint8_t makes a very big difference.) It can also make sense to use types like int_fast16_t when you are writing portable code - typically that will give you a 16-bit value on an 8-bit or 16-bit processor, but often a

32-bit value on a 32-bit processor.

Reply to
David Brown

I'd have to go back and look at the documentation, but IIRC they use one of the JTAG lines in a non-standard way as some sort of CPU clock or something.

--
Grant Edwards               grant.b.edwards        Yow! I own seven-eighths of
                                  at               all the artists in downtown
                              gmail.com            Burbank!
Reply to
Grant Edwards

ut

r
t
.

my

m.

So tell me how you would write a simple bss-init routine for TI TMS320C3x/c4x? These are floating point DSPs where binary 0 equals 1.0.

Reply to
wicore

That needs help from the compiler. Either the compiler needs to put uninitialized floats in the DATA section, with proper 0.0 initialization, or it needs to put them in a special BSS_FLOAT section where the start up code can loop through all variables, assigning them 0.0

Reply to
Arlet Ottens

Since wicore's posting was directed to me, I would also say that personally I am much more tolerant of implementation issues when a language is ported to a new architecture type which contains architectural specific issues which were probably not considered when the language was designed.

However, the OP is using a more traditional architecture on which this kind of initialisation is clearly expected as standard.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world
Reply to
Simon Clubley

Both are correct (assuming static floats are to be initialized to

0.0), and both are trivial to imlement.
--
Grant Edwards               grant.b.edwards        Yow! Do you have exactly
                                  at               what I want in a plaid
                              gmail.com            poindexter bar bat??
Reply to
Grant Edwards

I think we could assume that the rules for C were mostly developed by people working on PDP-11 processors. The MSP430 would feel very familiar to anybody who had worked with a PDP-11. The TMS320 not so much. Still, it's still trivial to do the right thing on a TMS320.

Just because something is easy and correct doesn't mean that TI will choose to do it that way...

--
Grant Edwards               grant.b.edwards        Yow! I'm having a
                                  at               quadrophonic sensation
                              gmail.com            of two winos alone in a
                                                   steel mill!
Reply to
Grant Edwards

I think they aren't necessarily trivial to initialize.

C requires 'semantic zero' and as pointed out above, this isn't always the same binary image for floats and doubles as might be used for integers on the same cpu. The static floats may be an element within a static structure rather than an elementary data type, so they cannot be so easily extracted and placed into a BSS_FLOAT as that would imply dragging the rest of the structure there, as well. Even with everything in the same static segment destined for startup initialization to semantic zeros, that problem remains. So I'd imagine that init code on such a cpu would be easier to handle if the compiler and linker cooperated to produce a non-volatile "image" and simply copied it into the segment prior to starting main(). Or a list of "patch up" pointers to those items which are initialized to something other than binary zero?

Jon

Reply to
Jon Kirwan

That seems to be the case. Apparently, the PDP-11 exposed some problems in B and BCPL.

formatting link

About like a staple-gunned, sawdust-board knock-off bookshelf reminds me of one decently designed and fabricated from select Cherry pieces that the cheap version was intended to mimic. It's when you put hands on the two that you know which is much better than the other.

Jon

Reply to
Jon Kirwan

Well, that would depend on the skill level of the person making the assessment. One person's trivial can still go way over another one's head. And people who dare consider themselves compiler writers had better be on the upper end of that spectrum. I.e. people for whom this is too hot should get out of compiler kitchen.

Indeed. That's about the point at which the very simplistic scheme of separating statics into .bss and .data starts to break down, and a more generic scheme of compressing the collection of initializers becomes preferable.

Once you realize that the concept of BSS vs. DATA is really just poor man's run length encoding, it becomes clear how to proceed from there: use a proper data compression algorithm in the linker to pack the complete ROM image of initialized data (including the implicitly initialized ones), and have the startup code unpack that into RAM, instead of just copying it. While at it, this also removes the problem the traditional BSS/DATA scheme has with variables like

unsigned int big_array[50000] = { 25 };

which would end up as a 50 KBytes full of zeroes in the DATA segment's ROM image for no particularly good reason.

Reply to
Hans-Bernhard Bröker

So it is not a simple process to make all uninitialised data 0 on the TMS320C3x. I don't /care/. The C standards say the compiler toolchain must do it, so any C compiler will clear uninitialised data to arithmetic 0 or pointer 0, as appropriate. If it doesn't do that, it is not a compliant C compiler.

There are lots of architectures that are horrible for C. It is hard to implement efficient local variables on an 8051 - yet people writing C compilers for the 8051 make the effort, because it is part of the requirements of the language they are implementing. If it is hard to write a bss initialiser for the TMS320C3x, then the CCS have no options but to work hard and write one.

Anyway, it is not that hard - a few c.a.e. regulars (yourself included) have come up with at least 3 different ways to do it. And no matter what challenges there might be for the TMS320C3x, it is a trivial task for the msp430.

Reply to
David Brown

I was merely arguing with 'trivial.' Had the word been 'simple,' I probably would have had no reaction. Trivial things are uninteresting, straightforward, and without nuance.

Jon

Reply to
Jon Kirwan

Fair enough.

Apologies if my post sounded a bit irritated - this whole issue has annoyed and frustrated me, even though it is easy enough to work around when you know of the problem. It is just so stupid, and so unnecessary to have this flaw in CCS that I go into "rant" mode when posting about it. Obviously it is not /you/ I am annoyed at - you are just helping explain some of the issues involved. So again, sorry if it sounded like I was annoyed at you or your post.

Reply to
David Brown

As someone else said, never assume anything.

Was doing some work with The Renesas 80c87 series recently, where the ide startup code examples do include code for initialisation, but to make use of it, you have to adhere to their standard layout and view of reality, which may not always be ideal.

In any case, it's always the responsibility of the programmer to initialise vars to their required values, usually through explicit module init functions. I do this from habit, even when I know that it has been cleared via the setup asm code. It's so little added effort and makes the intent clearer on the page...

Regards,

Chris

Reply to
ChrisQ

... and it's the compiler's responsibility to carry out what the programmer wrote, according to the only contract there is between him and the compiler: the definition of the programming language.

Compilers that don't fulfill even the most basic aspects of this contract aren't worth the space they take up on the disk even at todays rather modest costs for that commodity.

And while at it, it wastes code space. If you're never in a situation where that might risk breaking your entire project, consider yourself lucky --- or young.

Reply to
Hans-Bernhard Bröker

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.