Effecient assembly code to add to the timer channel registers

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Effecient assembly code to add to the timer channel registers

5,375 Views
FC
Contributor III
Hi,
 
Most of my programs are in C and I cannot determine the best way to code in assembly the following statement:
 
#define time_base 0xF424;
.
.
.
 
TPMC0V = TPMC1V + time_base; // Add input capture time + delay to TPMC0V
 
I became lazy and relied on the compiler to generate the assemby code which results in 34 clock cycles. 
 
The code is within the input capure ISR and basically adds the captured value + a predetermined delay to the output compare registers. 
 
The complication is the 16 bit value to be added. Is there a way in the assembler to indicate high and low bytes?
 
Thanks
Labels (1)
Tags (1)
0 Kudos
11 Replies

630 Views
rocco
Senior Contributor II
Hi, FC:

Again , assuming HC08, here is code from one of my GP32 ISRs:
;
; Add the ICR value to a constant offset and store in the OCR.
;
    lda    TPMC1V+1            ;  3 get the ICR value, low byte
    add    #LOW(time_base)     ;  2 add low byte of update rate
    tax                        ;  1 set aside for load
    lda    TPMC1V              ;  3 get the ICR value, high byte
    adc    #HIGH(time_base)    ;  2 add high byte of update rate
    sta    TPMC0V              ;  3 high byte must always be loaded first
    stx    TPMC0V+1            ;  3 low byte must always be loaded last
;                               = 17 cycles


If you are using an HCS08, I believe you no longer have the restriction that the low byte must be loaded last. In that case you can save 1 cycle by eliminating the TAX instruction.
0 Kudos

630 Views
bigmac
Specialist III

Hello FC,

A slight variation of Rocco's method that does not use the HIGH and LOW directives (not necessarily available for all assemblers).

lda    TPMC1V+1            ;  3 get the ICR value, low byte
add    #(time_base%256)    ;  2 add low byte of update rate
tax                        ;  1 set aside for load
lda TPMC1V ; 3 get the ICR value, high byte
adc    #(time_base/256)    ;  2 add high byte of update rate
sta    TPMC0V              ;  3 high byte must always be loaded first
stx    TPMC0V+1            ;  3 low byte must always be loaded last

Regards,
Mac

 

0 Kudos

630 Views
FC
Contributor III

Thanks for the responses.  I forgot to mention that its for the HCS08.

The assembler for CW 5.0 returns an error when the +1 is next to channel register. I have seen :smileyshocked: and :1 used before, what does the CW 5.0 assember use?

0 Kudos

630 Views
rocco
Senior Contributor II
Hi, FC:

CompilerGuru wrote:
To access a low byte from a 16 bit variable from assembly, just add 1 to the address of the variable. The HC08 is big endian, and therefore the low byte is at the higher address.

FC wrote:
The assembler for CW 5.0 returns an error when the +1 is next to channel register. I have seen :smileyshocked: and :1 used before, what does the CW 5.0 assember use?
Hmm . . . I could never get CW to work, so I'm still using MCUez. I wonder if this is why CW gives me thousands of errors? Sorry I can't be of more help there. Please let me know what you find out.

Since you use the S08, you can load the high/low bytes in either order, so the code becomes:
;
; Add the ICR value to a constant offset and store in the OCR.
;
    lda    TPMC1V+1            ;  3 get the ICR value, low byte
    add    #LOW(time_base)     ;  2 add low byte of update rate
    sta    TPMC0V+1            ;  3 load low byte of OCR
    lda    TPMC1V              ;  3 get the ICR value, high byte
    adc    #HIGH(time_base)    ;  2 add carry and high byte of update rate
    sta    TPMC0V              ;  3 load high byte of OCR
;                               = 16 cycles
0 Kudos

630 Views
bigmac
Specialist III

Hello Rocco, FC,

I have not been able to replicate FC's problem using CW 5.0 assembler.  The arithmetic on the register address seems to work fine.  I even added spaces before and after the + sign, again without problem (I thought I might have to add parenthesis in this case).  In fact, when I placed a colon in lieu of the + sign, I got an assembly error.

I assume that FC is actually using the assembler, rather than inline assembly within the C compiler.  The attached sample file assembles correctly using CW 5.0.

Regards,
Mac

 

0 Kudos

630 Views
CompilerGuru
NXP Employee
NXP Employee
The inline assembler wants offsets to be encoded with the colon syntax
LDD test:10
the assembler does expect offsets to be added with a +:
LDD test+10

My understanding of the idea behind this difference is that for the C compiler, things like "pointer+10" does mean something completely different than for the assembler (the real, non C/HLI assembler).

For the compiler, it means to read the pointer variable from memory and to add to this value 10 times the size of the type, the pointer points to.

For the assembler, it means to add 10 to the address of the pointer label.
(Well ok labels dont have addresses, they just are addresses, that's actually part of the differences in the meaning between C and asm).

So if the compiler would accept the pointer+10 syntax, then coded like this would behave strange, the HLI and the C part would really not access the same thing:

int * pointer;
#define ACCESS_POINTER pointer + 10
void test(void) {
int a= *(ACCESS_POINTER);
int b;
__asm LDD ACCESS_POINTER; // does not compile.
__asm STD b;
}


Daniel
0 Kudos

630 Views
rocco
Senior Contributor II
Thanks a ton, Mac!

Someday, I will try to get CW to work. But I can now sleep tonight knowing all of my code is not worthless.

I was in a serious panic for a couple of hours, there. Almost drove me to not drink.
0 Kudos

630 Views
FC
Contributor III
The assembler in CW 5.0 uses a :smileyshocked: (high byte) or :1 (low byte).
 
ex.
 
lda x:1
0 Kudos

630 Views
rocco
Senior Contributor II
Oh, God, that's awful!

After twenty-five years of using the + syntax, why would they want to change it? Does that mean that I have over a hundred thousand lines of code that CW won't ever assemble?

If management hears of this, we will be switching to AVRs and PICs. They have been hinting at this for a while now, with only the old code-base holding us back. If they find out Freescale no longer supports our old code, then nothing is keeping them from switching.
0 Kudos

630 Views
rocco
Senior Contributor II
Hello again, FC:

If you can finesse your timer so that the offset can fit in one byte, you could use the HC08s anemic 16-bit add, which can do it in 10 cycles. The offset would have to be either 0 through 127, or FFFF through FF00 (represented as -1 through -128).

Remember to push/pull the H register if you use this, which will add 4 more cycles if you are not already doing a PSHH and PULH.
;
; Add the ICR value to a SMALL constant offset and store in the OCR.
;
      ldhx    TPMC1V            ;  4  Get the ICR value
      aix     #time_base        ;  2  Add a small offset to it
      sthx    TPMC0V            ;  4  And store in the OCR
;                                =10 cycles
0 Kudos

630 Views
CompilerGuru
NXP Employee
NXP Employee
I assume this is for a HC08.
To access a low byte from a 16 bit variable from assembly, just add 1 to the address of the variable. The HC08 is big endian, and therefore the low byte is at the higher address.
0 Kudos