Moving from assembly code to C

Any experiences with "refactoring" assembly code to C or C++?

A different target CPU (due to obsolescence and future upgrades is the primary motivation)

This is an embedded application.

thanks for any ideas

Reply to
Mark
Loading thread data ...

I would treat the assembly code as defining the functionality and as a suggestion of _one_ way to organize the code and data. Then I would start a clean design in your target language, organizing the code and data in the way that is clear and makes sense, keeping in mind the possible upgrades.

Thad

Reply to
Thad Smith

The quick way would be to take the overall program, and replace each function call with a call to an equivalent C function, e.g.

LDAA #'a' CALL PRINT

would become

putch('a');

Then wrtie functions for everything not in the library.

Assuming of course that the assembler is written in such a helpful manner...

But as someone else has pointed out, the right way in the long term is to rewrite the lot starting from the functionality.

Paul Burke

Reply to
Paul Burke

The quick and dirty way is to translate the assembly code to C/C++ literally by replacing every assembly instruction with a macro. The good way would be to rethink the whole project and rewrite it in C/C++ from scratch.

Vladimir Vassilevsky

DSP and Mixed Signal Design Consultant

formatting link

Reply to
Vladimir Vassilevsky

You've got the source?! Wow. All I ever get is "Here's the ROM and they don't make that processor any more."

-- _ Kevin D. Quitt 91387-4454 snipped-for-privacy@Quitt.net 96.37% of all statistics are made up

Reply to
Kevin D. Quitt

i would think carefully before doing that. Most processors have very similar op codes, it should be quite easy to report, if a little tedious. C is all the rage these days but it has serious drawbacks on small processors.

Reply to
CBarn24050

I don't want to start a language war here, because embedded systems are all about managing compromises and divergent views of doing the same thing.

I, personally, am a strong supporter of judiciously using C, even for small (8-bit) microcontrollers. In my opinion, if you have a reasonably good compiler, you can write C code that would produce very efficient assembly.

I find C attractive mostly due to the fact that it is far more readable (even 5 years later), easier to maintain, easier to test and easier to port to new platforms, if the needs should ever arise.

One of the reasons C is bad for embedded systems is that there are way too many C programmers who work all loops using "int counter;" An integer is 16 bits even on an 8-bit platform and every time you do "counter++;" you invoke multi-precision arithmetic on the target! Such things don't happen in assembly because you are already thinking at the micro-level and do the equivalent of an "int counter" is painful.

In my opinion, if this is the first time you are targetting this platform in C, take some time to experiment with various C constructs on it. Get a compiler that produces intermediate assembly output that you see.

This way:

- you know what's expensive to do in C

- you can see how different contructs in C produce different assembly outputs (for example, loops counting up & down produce different sizes of code)

- you have a reference implementation to optimize in assembly if you need to

I'll end by giving two examples that I find useful when trading off C versus assembly. Both are for the 8051 platform using the Keil compiler.

**** EXAMPLE 1 **** ... 05 for (i = 0; i < 10; i++) 06 { 07 /* body of the loop */ 08 } ...

produces the following assembly:

*** ; SOURCE LINE # 5 CLR A MOV R7,A ?C0001: ; SOURCE LINE # 7 --- the body of the loop -- ; SOURCE LINE # 8 INC R7 CJNE R7,#0AH,?C0001 *** Loop setup: 4 instructions

On the other hand, re-ordering it to do a down-counting loop:

10 for (i = 10; i > 0; i--) 11 { 12 /* body of the loop */ 13 }

produces: ?C0002: ; SOURCE LINE # 10 MOV R7,#0AH ?C0004: ; SOURCE LINE # 11 ; SOURCE LINE # 12

--- the body of the loop --- ; SOURCE LINE # 13 DJNZ R7,?C0004

Loop setup: 2 intructions!

I don't think you can get more efficient than this (without going into rotating bits through the carry for signalling a count of 8) and this is written in C!!

**** EXAMPLE 2 **** At the same time, C is particularly bad at higher precision arithmetic. I won't post the code here, but take a look at the amount of work you need to do to find if your addition produces a carry:
formatting link

In assembly, this would quickly translate into the opcode for Add-With-Carry.

Anyway, in my opinion, it makes sense to code a good deal of yor apoplication in C and then find the bottlenecks and ease them out either by writing in assembly or improving the C. This way, you are likely to get a quicker time to completion, more confidence in your implementation and at an affordable overhead cost.

Best of Luck!

Cheers Mohit.

-- Join the Infineon TriCore Users Group Mailing List. Details -

formatting link

Reply to
Mohit Sindhwani

These days I try to do as much as possible in C. [On 8 bit micros mostly]

Yep, agreed. Those are my main reasons for using it.

Never had to do so and I suspect this "portability" concept of C is seriously overrated.

In that case they need to improve their programming skills. I just took a look at some stuff I wrote 4 or 5 years ago, I used "byte" counters and I would expect others to do the same. Then again I learned to programme in assembler about 10 years before I learned C and I would suggest all embedded programmers should learn assembler before C.

I often still scratch my head when trying to compose complex data structures and passing mechanisms in C which I could easily do in assembler.

Agreed.

Mike Harding

Reply to
Mike Harding

--- clip clip ---

I had - and got positively surprised how much it helped.

The conversion was from Intel 80C188 with Borland C to Atmel AT91R40008 (ARM7TDMI) with the GNU toolset. The controller (the Linet network controller ) had about 50 kilobytes of code and the conversion took about a week. A surprise was also that the ARM/Thumb code was pretty near of the same length as the Intel code.

Strongly agreed. There's no way to make good embedded code without looking at the assembly code - though the assembly code of the modern RISC CPU's is a PITA.

Tauno Voipio tauno voipio @ iki fi

Reply to
Tauno Voipio

I'm sure you're correct in that C is much easier to port than assembler but I just doubt how often embedded code _is_ actually ported. Of course we'll now get lots of responses from people who have done just that :) but if you consider how many embedded applications are written I suspect only a very very small percentage are ever ported to another CPU?

Mike Harding

Reply to
Mike Harding

code

ARM/Thumb

Not very often indeed.

Now there seems to be a burst of replacements to the 80186 family chips. For my customers, the recommended replacement is the AT91 series, so there has been a couple of the conversions and a dozen more in sight. The Linet conversion was the first and it was also kind of a pilot project which encouraged to do the others.

Still, the percentage is not very high - maybe 5 to 10 % of the long-lived designs. Pretty often there will be also other changes to the device architecture, so it's not a simple port anymore.

Tauno Voipio tauno voipio @ iki fi

Reply to
Tauno Voipio

Unfortunately that's a very big IF.

Ian

Reply to
Ian Bell

Hi Tauno

I take your point on the RISC CPU assembly being tough to read... but there are two important points here.

[1] RISC instruction sets tend to be more regular in what they do and I often get the feeling that the compiler does actually do most of the work and resonably well most of the time. CISC and CISC-like embedded processors have special instructions (like the DJNZ in the example I gave) that can affect the quality of the implementation and are, in my opinion, the more important reason to scan the assembly outputs. [2] The other point, and this can be argued, is that if you're usin RISC processors, you *probably* can afford the overheads of (at least) C, so reading the PITA-assembly is probably less crucial.

That's all Cheers Mohit.

Reply to
Mohit Sindhwani

looking

is

Yes - those conversions contained two pieces of obligatory assembly language coding:

- hardware startup - the core pieces of the multi-thread kernel.

In practice, the conversion involved rewriting the assembly pieces, but most of C could just be moved, despite of the different CPU architecture sizes (8/16 bits vs 32 bits).

Don't understand me that I did not read the generated assembly code - I'll keep doing it despite of the RISC peculiarities. The ARM is actually pretty assembler-friendly compared to e.g. Sparc or MIPS.

Tauno Voipio tauno voipio @ iki fi

Reply to
Tauno Voipio

similar op

the

formatting link
is a professional Asm to C tool. I've not used it.

Reply to
Bill Davy
[...re: Portability of C...]

You don't have to port an entire application to benefit from portability. The most obvious example I have is a simple serial communications protocol that was originally written for an 80186. I later ported that to PM 80386, an 80960, and an 8051.

Of course the UART handling codes were all different, and each application had its own interface code between the protocol and the application. But the protocol code itself required no changes at all until we put it on the 8051 (there were several routines with formal parameters named "data", which was a reserved word in the 8051 compiler).

Later I had to port to another 8051 platform, and because of limited memory had to locate the buffers in a particular area of memory (idata, IIRC). That didn't take long either, though it did require some source level changes...

Regards,

-=Dave

--
Change is inevitable, progress is not.
Reply to
Dave Hansen

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.