ASM v. C - Round 2:  Variables and Cycle Count

cancel
Showing results for 
Search instead for 
Did you mean: 

ASM v. C - Round 2:  Variables and Cycle Count

596 Views
LiveMike
Contributor II

ASM:

    ORG $0B00TEST DS 1    ORG $C000CLR TESTINC TEST

 C:

byte TEST;TEST = 0;void main(void){    TEST++;}

 The C code SINGLE LINE "TEST++;" disassembles to:

LDHX #TESTINC ,X

 In ASM "INC TEST" is 5 cycle counts

In the disassembled C, "LDHX #TEST  INC ,X" is 3 + 4 (7) cycle counts.

 

THIS IS VERY BAD.

 

I believe it has something to do with the variable type of TEST (byte), but I tried int, unsugned short, word and get the SAME disassembled code.

 

First:  in ASM what does adiing the "#" in front of TEST in "LDHX #TEST"??  Something to do with direct page RAM or something?

 

NEXT:  It seems odd you can Load HX with a variable, then INC ,X and it actually updates the variable.  Brings me back to the first question maybe the "#" is a pointer?

 

3rd:  WHAT CODE in C would DISASSEMBLE to the first example ASM code I gave.

In other words, I want "my_variable++;" to disassemble to "INC my_variable".

 

I posted before about the difference between a "REGISTER" in ASM and a "variable" in C, with no good explanation.  It seems this problem is bigger than I thought.

 

Finally, in my 30 pages (printed out - small font - meaning 100s of lines) ASM code I have 50+ REGISTERS (variables; single bytes allocated in memory) that I use (knowing they cant exceed 255) to store numbers like 4, 13, and 182 and update and manipulate them, do math ya know.  If I created this program in C, it would seems the "dissasembled" version would be full of "LDHX #my_var .. INC ,X" and the cycle counts of my code/program/routines would all be WAY WAY higher.  Again, THIS IS VERY BAD!

 

Any comments, answers, pointers, explanations would be great :smileyhappy:

 

Thanks in advance,

-Mike

Labels (1)
Tags (1)
0 Kudos
3 Replies

128 Views
bigmac
Specialist III

Hello Mike,

 

Firstly, you will need to gain an understanding of the various addressing modes available with HCS08 MCUs.  This is described within every datasheet and/or reference manual.  You will need to understand the difference between immediate addressing, direct addressing, extended addressing, and indexed addressing modes with zero offset, 8-bit offset or 16-bit offset.

 

Examination of the various assembly instruction details will reveal that some instructions are not capable of handling all the above addressing modes.  Instructions like CLR and INC fall in this category, along with many others.  In fact, the assembly snippet that you give should not assemble without error, because the variable TEST requires use of extended addressing mode, which the instruction does not support. 

 

To eliminate the assembly errors, you might use code similar to the compiled C example.  This code, which uses indexed addressing with zero offset, will work for a variable at any RAM location.  To clear the memory location would also require a similar construct.

   ldhx  #TEST  ; H:X contains variable address

   clr   ,x

 

If you were to explicitly define the variable TEST within zero page RAM (this would require the use of a #pragma), it is possible that the compiler may use the direct addressing instructions, but this cannot be guaranteed for all compilers.  You would need to check the actual compiler output.

 

As another example, the following C function

void incr_mem( byte *addr)  // Increment byte value at specific address

{

   *addr++;

}

 

could be represented by the following assembly code

 

; On entry, H:X = address of location to be incremented

INCR_MEM:

   inc  ,x

   rts

 

Keep in mind that the code generated by a C compiler will, in most cases, will require greater code size and more execution cycles, than well written assembly code, maybe by a factor of 2:1, or more.  This is the penalty for using a portable, higher level language, and why it can be necessary to use non-portable inline assembly code within time critical C functions.

 

Optimised assembly code for the HCS08 should attempt to use as few dedicated variables as possible, and make use of the stack for storage of intermediate values.  A similar situation exists for C, where the number of global and static variables should be minimized, in favour of local, stack based variables, where feasible.

 

I assume that what you actually mean by the term "register" is simply a labelled memory location, rather than referring to an internal register within the CPU.  A labeled memory location in assembly is equivalent to a global variable in C.

 

Regards,

Mac

 

0 Kudos

128 Views
LiveMike
Contributor II

First, the ASM ORG $0B00 should have been $00B0, which is the beginning of my (JM16) RAM, and INC etc. works fine.  This was a good catch (I guess) but extremely obvious, and not related to my question.  The "#" meaning immediate adressing I knew, but I didn't know what that meant.  The JM16 data sheet lists IMM/DIR/EXT/IX etc. for adressing modes for it's different instructions.  It's interesting the compiler in CodeWarrior 6.1 does check if the variable is in RAM (which it is) and still uses the LDHX, but oh well, and I understand extra bytes and cycle counts is part of using C, but that's exactly why our company has used ASM up intil recently and we are only testing to see if it is feasable to go with C.  BTW, as far as more cylces or bytes, in a dozen or so tests, the .s19 C generates is only about 10% more bytes, and most cycle counts are only about 5% higher.  This line "I assume that what you actually mean by the term "register" is simply a labelled memory location, rather than referring to an internal register within the CPU.  A labeled memory location in assembly is equivalent to a global variable in C." makes no sense to me.  A register in ASM is a byte in memory.  A PIN definition register, a SC register, or a "variable" aka TEST DS 1.  Now TEST is allocated to 1 byte and I can store any number there from 0-255 (decimal), 00-FF (hex), or 00000000-11111111 (bin) which all are useful.  I can then LDA, STA, INC, DEC, etc.

 

MY ORIGINAL QUESTION is is there a variable typr in C that is ONE BYTE where lets say it was 250 and you added 10 it would then become 4.  You could load it into the ACCUMULATOR without having to use LDHX because once again it is only ONE byte.  int, short, long, are all allocated to more than one byte in memory, what a waste to store the number 4.  But if the compiler is still going to use LDHX because it doesnt check the memory location (zero page) of the variable, I guess it doesn't matter.  When the application demands accuracy within a microsecond and there is limited Flash (16,384) bytes etc.  Limited RAM, occasional USB RAM, all of these questions come into play, and knowing exactly what is going on to a chip is mandatory -even down to manually editing the .s19 before flashing.

0 Kudos

128 Views
kef
Specialist I

You should get C book, also have a look at CPU08 reference manual or at RM of your device, which should include chapter about CPU and available addressing modes. # stands for immediate addressing. ldhx #0x123 loads H:X with 0x123. INC test doesn't work for variables with address >=0x100. That's why C loads address of var into HX first, and then increments it. You asm code doesn't work for test at 0xB00.

0 Kudos