We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello, I was browsing through older posts that deal with the painful issue of portability (http://www.keil.com/forum/docs/thread8109.asp). I was (and still am) a big advocate of programming as much as possible conforming to the C standard, and having a layered structure that allowed "plugging-in" other hardware. But I have come to change my mind recently. I am reading the "ARM system developer's guide" (excellent book by the way. I'm reading it because I want to port some C167 code to an ARM9 environment) in which chapter 5 discusses writing efficient C code for an ARM. The point is, and it is fairly demonstrated, that even common, innocent looking C code can either be efficient of very inefficient on an ARM depending on specific choices made, let alone another processor used! So, if we are talking about squeezing every clock cycle out of a microcontroller - I do not believe that portability without ultimately littering the code is possible!
The only reason I can see for "changing tool vendors" would be that you made a mistake initially and bought bug-ridden tools.
For the 8051 I've used Intel, Archmedes, Avocet, IAR, Whitesmith, BSO-Tasking, etc, etc, and Keil assemblers/linkers/compilers. (Yes, I know they're all practically derivative works from each other). So I'm familiar with variations in implementations of the "C" standard (and even then, "C" was evolving). So yes, they were all bug-ridden tools and we [the industry] corrected that mistake as the tools got better, companies changed ownership, and technology improved. (Just a guess, but I'll bet that pattern will continue in the future).
Other reasons include:
Your company might decide to change tool suites for bizzare reasons like the new tool set comes with a neat-o key-fob the boss wants so he mandates that the new tool IDE will now be Crapoli Version 1.03 by Off-Brand Corp.
Or, you don't want to be forced to find that old Keil uVision 1.03 compiler in order to add a small feature to an old product.
Or, your company gets bought-out by Big-Fish Incorporated, and they have the new wiz-bang mega-buck tool set. Your code now needs to comply.
Or, you are doing work for the government and they want to make sure that it can be re-created ten or twenty years from now. And they don't want to resurrect Archimedes Inc just to recompile the code.
Or your product, and the associated code, might be sold to a company that uses XYZ and not your company's ABC.
Or, if you do contract work, company X might expect your source code to work on their XYZ compiler... but you use the ABC's compiler at home.
Or, you are a veteran engineer who has a library of tried-n-true code snippets that are qualified to the nth degree, and you want to be able to use them even though ARM was bought-out by Altium and Keil was summarily killed because it conflicted with their IAR products. Altium then gets purchased by the newest CAD mega-giant CEIBO, but CEIBO becomes merely a pawn in the Microsoft vs Apple war of 2012. The US government wins that war by seizing all the assets of both companies and now, by law, you are compiling your code using Oracle Corporation's UberBloat "C" IDE. You never know what is going to happen... code defensively.
If you have project 'x' running with tools 'a' and switch to tools 'b' what is hindering that you maintain 'x' with a'
If you ensure that the development tools are also archived with each revision of code, then you shouldn't have a problem with 'x' and 'a' but since that is not always the case, nor is it always do-able because of licensing problems, I would say that time hinders it.
erik, I do agree with you on the "udder stupidity" of the 'help-desk'!
They don't get the engineering environment like we do. The word processor's upgrade will still read those old documents just dandily, why won't the IDE also be able to read the ".C" files? Remember, they're not engineers for a reason.
LOL-- the mechanic finds the culprit: root cause fixed and documented with a chalk outline.
--Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA
Per, I meant the "IT department" instead of "Help desk", of course.
Do you think that what the help desk did was stupid, or that my statement was stupid? I don't think so! If you mean the later, well, good luck to you in verifying your software consistency and your test plan! what the help desk did was stupid, I thought that was crystal clear.
there is an expression "do not change horses in the middle of the stream"
Erik
Vince, what you write is very true, but to make code 'portable' for that laundry list would make the portability effort far exceed the effort put in the working code.
I have been through a compiler change ot two and, in each case, said to myself, thank heaven for CodeWright.
A port (of non-portable code) is relatively painless when you have an intelligent editor.
However, there are some things that both make coding and porting easier such as, for example, the small example of mine below.
// pointer in data in #define U8DI unsigned char idata * data // data idata #define U8DX unsigned char xdata * data // data xdata #define U8IX unsigned char xdata * idata // idata xdata #define U8XX unsigned char xdata * xdata // xdata xdata #define U8IC unsigned char code * idata // idata code #define U8DC unsigned char code * data // data code #define U8XC unsigned char code * xdata // xdata code #define U8CC unsigned char code * code // code code #define U16DX unsigned short xdata * data // data xdata #define U16IX unsigned short xdata * idata // idata xdata #define U16CC unsigned short code * code // code code #define U16DC unsigned short xdata * data // data xdata #define U32DX unsigned long xdata * data // data xdata #define U32DC unsigned long xdata * data // data xdata
I even went to my boss at the time to complain but to no avail. but what can you expect from somebody that makes statements like this: "I won't ask him why he does not bother to run a static code analyzer, because then I will have less ammunition to bust his ass if it does wrong". shocking, really.
Please explain these two:
#define U16DC unsigned short xdata * data // data xdata #define U32DC unsigned long xdata * data // data xdata
Your U16DC seems to be a U16DX and your U32DC seems to be a U32DX.
thanx,
I evidently got an old uncorrected one.
I am working from home and much stuff has not ben made urrent
I was (and still am) a big advocate of programming as much as possible conforming to the C standard, and having a layered structure that allowed "plugging-in" other hardware. But I have come to change my mind recently.
I'm not sure from this whether you've made up your mind about changing you mind...
The point is, and it is fairly demonstrated, that even common, innocent looking C code can either be efficient of very inefficient on an ARM
I'm interested - if the example is reasonably concise could you post it?
So, if we are talking about squeezing every clock cycle out of a microcontroller - I do not believe that portability without ultimately littering the code is possible!
If every last clock cycle counts then changing processor or increasing clock speed would seem a better option. If neither of these is feasible then accept that the design is inadequate, code the necessary bits in assembly then start work on the MK2 replacement system as quickly as possible.
If every last clock cycle counts then changing processor or increasing clock speed would seem a better option. rephrase "then changing processor or increasing clock speed would seem a costlier option" The OP has not revealed the (planned) production volume of his thingy, but if it is significant then ...
If neither of these is feasible then accept that the design is inadequate indequate??? if it is doable, working and there are cost constrains, where do you get 'inadequate' from
code the necessary bits in assembly A reasonable approach, but if "processor pleasing C" will do, then why not use that?
then start work on the MK2 replacement system as quickly as possible. and go bankrupt becuse your product is more expensive than the competitors.
If the world rotated about "standard C" and "programmers convenience" instead of business realities then ...
Please go to the nearest paharmacy and buy a dose of reality
Ok Jack, here you go:
int checksum_v5(int *data) { unsigned int i; int sum=0; for (i=0; i<64; i++) { sum += *(data++); } return sum; }
This compiles to
checksum_v5 MOV r2,r0 ; r2 = data MOV r0,#0 ; sum = 0 MOV r1,#0 ; i = 0 checksum_v5_loop LDR r3,[r2],#4 ; r3 = *(data++) ADD r1,r1,#1 ; i++ CMP r1,#0x40 ; compare i, 64 ADD r0,r3,r0 ; sum += r3 BCC checksum_v5_loop ; if (i<64) goto loop MOV pc,r14 ; return sum
It takes three instructions to implement the for loop structure:
*An ADD to increment i *A compare to check if i is less than 64 *A conditional branch to continue the loop if i < 64
This is not efficient. On the ARM, a loop should only use two instructions:
*A subtract to decrement the loop counter, which also sets the condition code flags on the result *A conditional branch instruction
The key point is that the loop counter should count down to zero rather than counting up to some arbitrary limit.
Now, an improved verison is this:
int checksum_v6(int *data) { unsigned int i; int sum=0; for (i=64; i!=0; i--) { sum += *(data++); } return sum; }
checksum_v6 MOV r2,r0 ; r2 = data MOV r0,#0 ; sum = 0 MOV r1,#0x40 ; i = 64 checksum_v6_loop LDR r3,[r2],#4 ; r3 = *(data++) SUBS r1,r1,#1 ; i-- and set flags ADD r0,r3,r0 ; sum += r3 BNE checksum_v6_loop ; if (i!=0) goto loop MOV pc,r14 ; return sum
Say, Jack, are you going to read the manual for a change :-) :-) ;-)
Loop unrolling?
Yes Per, another excellent example, but I think that the example above is more powerful as it depends on the actual instruction set of the processor.
Just about all processors prefer loops that decrement to zero, since zero is "magic".
In this case it takes a decrement and a conditional branch. A lot of processors has DJNZ instructions, where a hard-coded register is used to fit all in a single instruction.
If every last clock cycle counts then changing processor or increasing clock speed would seem a better option
So efficient programming does not count in your school? Knowing your tool and hardware, as you so often preach, is the key!
Given that the loop counter is not used in or after the body of the loop the compiler is, I believe, well within its rights under the 'as if' rule to rearrange the loop to decrement rather than increment. I guess it's a quality of implementation issue.
If you decide to code loops like this to decrement rather than increment the resulting 'C' is no less portable, so I'm not entirely sure what your point is.
If you mean that you would have to perform this kind of manual optimisation for each platform and/or compiler you target then I congratulate you on being able to design hardware that is only just powerful enough to work with optimal code every time.
If 'every clock cycle counts' then you have to use assembly. 'C' will always produce code that is slower and larger - the problem is that you cannot predict by exactly how much. If this matters, don't use 'C'.
Say, Jack, are you going to read the manual for a change
I don't use ARM.