This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

>> convert to RR not RRC

Hi,

I need to put a statement in a interrupt routine to shift a variable right one-bit. Like this:

dat >>=1;

It generated assembly code like this:

MOV A,dat
CLR C
RRC A
MOV dat,A

What statement in C language sould be written to complete the shift operation but not effect the "C,carry" bit?

This is to save the "PUSH PSW", "POP PSW" instruction in my ISR. The inline assembly statement is not good to me, since I am not familar with it.

Thanks, John

Parents
  • What statement in C language sould be written to complete the shift operation but not effect the "C,carry" bit?

    This is probably the wrong approach. The "statement" and whether it exists or not may change depending on things like optimization settings, compiler type, and compiler revision.

    Also, I doubt that the C compiler would actually recognize this kind of "hack" - because it would require:

    MOV A,dat
    RR A
    MOV dat,A
    ANL dat, #0x7F
    

    in order not to disturb the parity bit and open a completely different can of worms by introducing atomicity issues (if the ISR can be interrupted by a higher priority interrupt that also accesses dat, and this happens after "MOV dat, A", dat may contain an invalid value).

    Also, this would only save 2 CPU cycles compared to the approach that uses RRC.

Reply
  • What statement in C language sould be written to complete the shift operation but not effect the "C,carry" bit?

    This is probably the wrong approach. The "statement" and whether it exists or not may change depending on things like optimization settings, compiler type, and compiler revision.

    Also, I doubt that the C compiler would actually recognize this kind of "hack" - because it would require:

    MOV A,dat
    RR A
    MOV dat,A
    ANL dat, #0x7F
    

    in order not to disturb the parity bit and open a completely different can of worms by introducing atomicity issues (if the ISR can be interrupted by a higher priority interrupt that also accesses dat, and this happens after "MOV dat, A", dat may contain an invalid value).

    Also, this would only save 2 CPU cycles compared to the approach that uses RRC.

Children
  • You may want to experiment with the intrinsic routines, though:

    http://www.keil.com/support/man/docs/c51/c51__cror_.htm

    Maybe a

    _cror_(dat, 1);
    dat &= 0x7F;
    

    has the effect you are looking for, if the compiler acutally inlines the _cror_ and doesn't use a function.

  • Yes, it is not a good way in general application.
    But by strict ISR time requirement, I'm forced to find a way to save the time as more as I can.

    P.S.
    1. This ISR is define to be the only one high priority interrupt.

    2.PUSH and POP cost total 48 cycle on my system, it takes nearly 1.2 microsecond(40MHz,12T), but this ISR limited to complete task in 20 microsecond.And it happened to be the module of system with most time-sensitive.

  • "this would only save 2 CPU cycles compared to the approach that uses RRC."

    IF your application really is so critical that this is important (which may well be the case), then you are certainly going to have to be writing parts of it in assembler - and that's not just slapping down any old assembler; that will require skilful, hand-crafted, carefully-tuned assembler.

  • I'm forced to find a way to save the time as more as I can.

    In that case, you'll have to dive into assembly.

    The compiler does several things that usually don't mix well with tight timing constraints in interrupts.

    For example, it always locates the ISR somewhere in program memory, and performs a LJMP from the interrupt vector table to the start address of the ISR, even though there are 8 bytes available in the vector table that can hold a complete (yet short) interrupt service routine.

  • cror_(dat, 1);
    dat &= 0x7F;
    

    Above program is not correct, it won't process the rotation, and it can corrected to follow one.

    dat = cror_(dat, 1);
    dat &= 0x7F;
    

    But the _cror_ is not a good choice, it cost more time than ">>". The assembly code after complied is listed as below.

    Dear Christoph, still very thanks for your suggestion.

    0053 AF00        R     MOV     R7,dat
    0055 7801              MOV     R0,#01H
    0057 EF                MOV     A,R7
    0058 08                INC     R0
    0059 8001              SJMP    ?C0016
    005B         ?C0015:
    005B 03                RR      A
    005C         ?C0016:
    005C D8FD              DJNZ    R0,?C0015
    005E F500        R     MOV     dat ,A
    0060 53007F      R     ANL     ps2dev_kb_rxdata,#07FH
    


  • In that case, you'll have to dive into assembly.

    I agree now.
    It is the last thing I can do after I re-contrust the data structure to eliminate more control statement.

    So far, it is hard to keep the state machine tight and clear.

  • "2.PUSH and POP cost total 48 cycle on my system, ..."

    Given your tight timing budget, writing the whole ISR in assembly seems really to be your best way.

    The context saving/restore code can be effectively optimized if you use banked registers. By selecting the ISR bank in RS1:RS0 you save 8 push/pop instructions. If your ISR handler can be written using only the 8 banked registers, you don't even need to set up local variables, since the ISR banked regs will hold their value between interrupts.

    About the RR/RRC:
    Using

        CLR C
        RRC A
    


    takes one program byte less than

        RR  A
        ANL A, #0x7F
    


    ... and you can always save the CLR C by preceding the RRC A with an operation that guarantees leaving the carry cleared.