Archive for the ‘Compilers / Tools’ Category

Is GCC a ‘good’ compiler?

Tuesday, February 2nd, 2010 Nigel Jones

It seems that barely a month goes by when I’m not asked my opinion on compilers. Sometimes I’m simply asked what compilers I use, while other times I’m asked my opinion on specific compilers – with GCC being by far the most asked about compiler. I’ve resisted writing about this topic because quite frankly it’s the sort of topic that people get very passionate about – and by passionate I mean frothing at the mouth passionate. It seems that some folks simply can’t accept the fact that someone doesn’t agree with them that XYZ is simply the best compiler ever. Notwithstanding this, the volume of inquiries has reached the point where I really feel the need to break my silence.

First of all lets make some general observations.

  1. Despite the fact that I’ve been doing this for nearly 30 years and also despite the fact that as a consultant I probably use a wider variety of compilers than someone that works for an employer, the simple fact is that I’ve only had cause to use in anger a limited number of compilers. Thus are Rowley compilers any good? Well their website is decent, the documentation is OK and the IDE very nice. However I’ve never built a real project with their tools and so I really don’t know whether Rowley compilers are any good.
  2. Many vendors provide compilers for many targets. As such it’s a good bet that if their 8051 compiler is very good, then their ARM compiler is also likely to be excellent. However it isn’t a given. Thus while I whole heartedly endorse the Keil 8051 compiler, I have no opinion on their ARM compiler.
  3. Compilers vary in price from ‘free’ to ‘cheap’ to ‘expensive’ to ‘they have got to be joking’. I’ve put all of these costs in quotes, because as you’ll see below, one’s perspective on what constitutes ‘free’ or ‘expensive’ is not easily defined.

So, enough with the preamble. Lets start with the ‘free’ and ‘cheap’ compilers, including GCC. Well for me the bottom line (literally) is that I can’t afford to use these compilers. The reason is quite simple. I’m a high priced consultant. I can charge high hourly rates in part because I have exceptionally high productivity. Part of the way I achieve my high productivity is by not wasting my time (and hence my client’s money) on stupid issues unrelated to the problem at hand. Given that a compiler / linker is such a frequently used tool, and given that I’m also the sort of engineer who pushes his tools hard, it’s absolutely essential to me that when I run into a compiler issue I can pick up the phone and get an intelligent response ASAP. One simply can’t do that with ‘free’ or ‘cheap’ compilers, and thus too often one is reduced to browsing the Internet to find the solution to a problem. When this happens, then my ‘free’ compiler rapidly starts to cost an arm and a leg.

What always amazes me about this topic is that so few employers / engineers seem to understand this. It seems that too many folks will eschew paying $2000 for a compiler – and then happily let their engineers bang their heads against a problem for a week – at a rate of at least $1000 a day.

Thus for me, the answer to the question ‘Is GCC a good compiler?’ is ‘no, it isn’t’. Of course if you are a student, or indeed anyone who is cash poor and time rich, then by all means use GCC. I’m sure you’ll be very pleased with the results and that you’ll find it to be a good compiler for you.

What then of the ‘expensive’ and they ‘have got to be joking’ categories? Rather interestingly, although based on limited experience, I’ve found that the very expensive compiler vendors ($10K+) also have lousy support. Instead it’s the ‘expensive’ vendors that actually seem to offer the best combination of functionality, code quality, support and price – and it’s this category that I tend to use the most.

Finally, regarding which compiler vendor I use. I happen to be a fan of IAR compilers. I’ve always found their code quality to be at least ‘good’. Their linker is probably the easiest and most powerful  linker I’ve ever used. Their support is very good (thanks Steve :-)). Finally their IDE is easy to use and has a very consistent look and feel across a wide range of processors, which is important to me as I tend to switch between architectures a lot.

Home

Using Espresso to simplify embedded systems

Sunday, January 18th, 2009 Nigel Jones

In this case, Espresso does not refer to the highly caffeinated drink, but rather to the public domain logic minimization tool. What does this have to do with embedded systems? Well, several months back I was faced with an interesting problem. A product I was working on had nine different alarm outputs (some of which are contradictory), which together were dependent upon about thirty different inputs. Furthermore, the interaction between the various inputs leads to situations where the desired alarm outputs are non obvious, and certainly difficult to determine algorithmically. At this point I realized that what was needed was essentially a giant truth table, where the outputs for any given set of inputs was determined by an expert who could look at the various inputs and determine the optimal alarm strategy. Thus the question was, how to tackle this problem? This is what we ultimately ended up doing. First of all the truth table was entered in a database. This was done simply so that we could easily run queries, such as “show me all cases where output 3 is asserted when inputs 6 12 and 13 are negated”. This essentially then was the environment in which the human expert worked. Once the expert was happy with the truth table, it was outputted in CSV format. The CSV file was then pre-processed by a Perl script (thanks Don) and fed to the Espresso logic minimization program. The output of Espresso was then post-processed by the Perl script and converted into compilable C code. To give you a feel for what the output looks like, here’s an excerpt (with the comments removed):

 if(((!(inputs[0] & 0x20)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10) && (!(inputs[3] & 0xa0))) ||
    ((!(inputs[0] & 0x20)) && (!(inputs[1] & 0x60)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x20)) && ((inputs[2] & 0x4) == 0x4) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x20)) && ((inputs[1] & 0x1) == 0x1) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x20)) && ((inputs[2] & 0x2) == 0x2) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x24)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x28)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x30)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x20)) && (!(inputs[1] & 0x4)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)))
{
 out |= 2048;
}

Evidently, it’s enough to make your head spin! For me, the real benefits of such an approach are as follows:

  • I was able to completely divorce the code from the desired functionality. That is, the functionality of the product was completely driven by the client and was in no way dependent upon me doing anything. Thus, when the client asks me ‘what does it do when the following occurs”, I can honestly answer “it’s whatever you told it to do”.
  • By setting this up using a database and a Perl script we recognized that changes to the truth table would inevitably occur, and thus made the process as painless as possible. Now, when a change in functionality is desired, the client simply makes the changes in the database, presses a button to output a new file and I then run a ‘make’.
  • The approach is rigorous. We have considered every possible combination of inputs – no matter how unlikely they are to occur. In my experience, this is something that firmware is not very good at.

Although I think this is neat in its own right, I think there are several larger points worth making:

  • Just because a tool was designed ostensibly for one environment (in this case Espresso was really designed for logic minimization in electrical circuits), don’t be afraid to use it in other ways.
  • Recognize that certain elements in your design are highly prone to change – and design them with this in mind.
  • Either learn a scripting language or have a scripting expert at your disposal to help build your tool sets. (In my case, I do the latter).
  • If you can divorce your code from the required functionality (i.e. data driven coding), then seriously consider it.

An apology

For all of you that subscribe via RSS, I apologize for the recent blitz of data. I decided to go back through all my postings and add links where appropriate, which seems to have forced the posts to be regenerated.

Home

Using volatile to achieve persistence!

Sunday, January 11th, 2009 Nigel Jones

Once in a while the real world and the arcane world of language standards collide, resulting in surprising results. To see what I mean, read on …

Many of the products I design incorporate a Bootstrap Loader, so that the application firmware may be updated in the field. In most cases, the bootstrap loader is a completely different program to the main application. Despite this, I find it useful for the main application to pass information to the bootstrap loader and vice versa. Thus the question arises, how best to do this? Well in the processor family I am using, although it is technically possible to store information in Flash, EEPROM or RAM, by far the easiest and most secure way of doing it is to place the information into EEPROM. Furthermore, in order to enter the bootstrap loader it is highly desirable to force a reset of the processor by allowing the watchdog timer to time out.

Thus, the code to enter the bootstrap loader looks something like this:

__eeprom uint8_t msg_for_bootloader;

...

msg_for_bootloader = 0x42;

...

for(;;)
{
 /* Wait for watchdog to generate a reset and force entry in to the bootstrap loader */
}

Well, on the face of it, there is not much wrong with this code. However, if one turns on the optimizer, then the compiler examines the code, decides that no code may be executed beyond the infinite loop and thus concludes that the write to msg_for_bootloader is pointless, and promptly optimizes it away. (For a discussion on this topic, see my posting here)

Now you will note that msg_for_bootloader was qualified with __eeprom. This is a compiler extension that allows one to inform the compiler that the variable msg_for_bootloader resides in a special memory space and to be treated accordingly. Now I know that the compiler knows enough about the EEPROM space to generate the correct coding sequences such that reads and writes are performed correctly. However, in my naivete, I also assumed that the compiler knew something about the properties of EEPROM, such that it would realize writing to EEPROM without ostensibly reading it again is intrinsically useful in many applications.

Well it does not. Furthermore, on balance I think the compiler writer’s got it right and the error was completely mine.

So what to do? Well, declaring msg_for_bootloader as volatile fixes the problem. Thus my code now looks like this:

__eeprom volatile uint8_t msg_for_bootloader;

...

msg_for_bootloader = 0x42;

...

for(;;)
{
 /* Wait for watchdog to generate a reset and force entry in to the bootstrap loader */
}

Thus I ended up in the rather bizarre situation of having to declare a variable as volatile in order to make it persistent!

Although I can appreciate the wry irony of this situation, I think it points to a larger problem. The fact is that we are all (ok, most of us) programming in a language (C) that was not designed for use in embedded systems. Indeed, when C was written, I’m not sure EEPROM even existed. As a result, the compiler vendors have added extensions to the C standard in an effort to overcome its shortcomings for embedded systems, while still desperately striving to achieve “full compliance with the standard”. Despite this, I find myself all too frequently falling into traps such as this one. What we really need is a language explicitly designed for embedded systems. It isn’t going to happen, but it doesn’t stop me wishing for it.

Home

Low cost tools

Thursday, September 4th, 2008 Nigel Jones

Like many of you, I subscribe to Jack Ganssle’s newsletter (If you don’t then you should – go to http://ganssle.com/). In his latest newsletter #164 (alas not yet posted to the web) there is a thread on tools for monitoring serial protocols such as I2C. I was quite interested in this because it so happens I use some of the tools mentioned. What really struck me though was the fact that someone was looking for low cost tools.

I’m always baffled when I see this. If I believe the salary surveys, most engineers in the USA are earning well over $100K. Throw in benefits and your average engineer costs his / her employer about $200K a year, or close to $100 per working hour. Why then do employer’s balk at spending a few thousand dollars on a decent tool? I’ve seen people spend days on compiler problems because they are using a “free” tool; I’ve had people tell me that they don’t use Lint because it’s too expensive (<$400!); I’ve seen people struggle for days simply because their oscilloscope isn’t up to the job. In all these cases, the cost in terms of their time dwarfs the equipment / tool cost.

What I want are great tools. I want tools that are intuitive to use, that work really well, are tolerant of my occasional ham-fistedness and that I trust. For example, I have a Fluke 87 multimeter sitting next to me. It costs quadruple what a Radio Shack special costs. It’s worth every penny.

Here’s an ending thought. You are going in for open heart surgery. The surgeon comes out and says “don’t worry – I’ve got some great low cost tools to use on you”. And we wonder why engineers don’t get the respect that doctors do.

Home

Have you looked at your linker output file recently?

Tuesday, August 12th, 2008 Nigel Jones

Of all the myriad of files involved in a typical embedded firmware project, probably the two most feared (and yes I do mean feared) are the linker control file (which tells the linker how to link your application) and the linker output file. Today it’s the latter which I’ll be talking about.

The linker output file tells you a myriad of information about the way your application has been put together. Unfortunately, much of it is in such a cryptic format that examination of the file is a painful process. Indeed, for this reason, I suspect that most projects are completed with nothing more than a cursory look at this file.

This is a shame, because examination of the linker output file can significantly reduce your debugging time. To show you what I mean, consider my typical action sequence when I first start coding up a project.

1. Write a module.
2. Compile module and correct all errors and warnings.
3. Lint module and correct all complaints from Lint.
4. Repeat steps 1, 2 & 3 until I have sufficient modules to be able to generate a linkable image.
5. Link image and repeat steps 1-4 until the linker has no warnings or errors.
6. Examine the linker output file.

I’d wager that most developers out there would be reaching for the debugger in step 6. The reason I do not, is because I can typically find some bugs simply by looking at the linker output. For example, consider this code sequence:

if (0 == var)
{
 function_a();
} else if (1 == var)
{
 function_b();
}
else if (2 == var)
{
 function_b();
{
else
{
 function_d();
}

I make these sort of copy and paste errors all the time. In this case, when var is 2, I meant to call function_c but inadvertently I ended up calling function_b again. Since function_b exists, the compiler is happy and so there are typically no warnings.

So how does looking at the linker output file help me in this case? Well, if you have a decent linker it will give you a list of all the functions that aren’t called and that consequently have been stripped out of the final image. If in perusing this list I see that function_c() is listed as uncalled, then I immediately know I’ve got a bug somewhere. Typically tracking it down is very easy.

I’ll leave for another day the other ways I use the linker output file to debug code.

Home