This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Why 9 single-cycle commands are perfomed for about 30 cycles?

Hi,

I have a problem - can`t understand why code execution time in RUN mode is about 30 cycles, while in STEP-by-STEP mode is onle 9 cycles!

I write small program:

volatile Uint16 i=0; 

void main(void)
{
    peripherial_init();                             // timer0 - init,... etc, all interrupt disable!

    CpuTimer0Regs.TIM.all = 1000; // 
 
    i++;
    i++;
    i++;
    i++;
    i++;
    i++;
    i++;
    i++;

    while(1) {}; 

And if I set breakpoint on the infinite loop and make RUN command   than value  CpuTimer0Regs.TIM.all = 969.  So it mean that eight (i++) instructions performed for about 30 cycles!  But if I use STEP-by-STEP then CpuTimer0Regs.TIM.all = 991.  

Somebody please help me to understand why it happens?  Thanks!

 

PS:  TIMER0 was init correctly.  Assembler code of eight (I++) instructions is:

//30 i++;
0x00029B: 761F001B MOVW DP,#0x001B
0x00029D: 0A12 INC @18
//31 i++;
0x00029E: 0A12 INC @18
//32 i++;
0x00029F: 0A12 INC @18
//33 i++;
0x0002A0: 0A12 INC @18
//34 i++;
0x0002A1: 0A12 INC @18
//35 i++;
0x0002A2: 0A12 INC @18
//36 i++;
0x0002A3: 0A12 INC @18
//37 i++;
0x0002A4: 0A12 INC @18


  • The cycle count is given for execution from zero waitstate memory.

    You can only get it when executing from internal ram and when all variables accessed are also in internal zero-waitstate ram.. Flash has waitstates, so when you execute your code from flash, you will see the waitstates, too.
    You could also have pipeline stalls when read is <= 3 cycles after write.

    When debugging via single-step, the waitstates and pipeline stalls do not count.

    So for real execution count, your higher value seems to be okay - do not measure cycle count via single step.

  • Alexander, Stephan

    you also have to take into account the behaviour of the JTAG - Interface, which is different in single step and real time run mode. All peripherals have two control bits "Soft" and "Free" (see register TCR. bits 11 ansd 10 of CPU timer 0).

    If these bits are set to "run free" then the CPU timer will continue to clock, when the code hits a breakpoint in real time run. The JTAG interface will take some cycles to read your variable from timer 0 to update the CCS window. In that time the CPU timer 0 counter has been already incremented by some numbers. In single step mode that update is quicker.

    To measure the performance of a code sequence I always prefer to set an output pin on entry and clear it on exit and to use a scope. 

     

     

  • Frank, Stephan thanks for reply.

    In my example I use only internal  zero waitstate RAM memory and "Timer Free Run Disabled" mode (TCR.bit.SOFT = 0; TCR.bit.FREE = 0)

    When I use output "set - clear" pin  to scope the test I get the same result -  time to perform 9  single-cycle commands is greatly more than 9 clocks. For SYSCLKOUT=50Mhz (20nS cycle) time for executing 9 commands is about  600 nS. But I expect for 180 ns = 9 * 20 nS.

    Therefor the question is opened.

  • Alexander Mazalov said:
    When I use output "set - clear" pin  to scope the test I get the same result -  time to perform 9  single-cycle commands is greatly more than 9 clocks. For SYSCLKOUT=50Mhz (20nS cycle) time for executing 9 commands is about  600 nS. But I expect for 180 ns = 9 * 20 nS.

    Alexander Mazalov said:

    0x00029D: 0A12 INC @18
    //31 i++;
    0x00029E: 0A12 INC @18
    //32 i++;
    0x00029F: 0A12 INC @18
    //33 i++;
    0x0002A0: 0A12 INC @18
    //34 i++;
    0x0002A1: 0A12 INC @18
    //35 i++;
    0x0002A2: 0A12 INC @18
    //36 i++;
    0x0002A3: 0A12 INC @18
    //37 i++;
    0x0002A4: 0A12 INC @18

    Alexander,

    Think about this from the pipeline viewpoint.  The pipeline from decode 2 is: D2  R1  R2  EXE  W

    Notice that write is at the end of the pipeline while read is earlier.

    Now, each of the instructions above is accessing the same location and is a "read-modify-write" instruction.

    The write associated INC # 31has to finish before the read of INC #32 can occur.  This is called write followed by read protection and because each access is to the same memory location it is guaranteed by the CPU.

    This creates a pipeline stall - Remember Read is before Write - so the pipeline will stall INC #32 in the pipleine until the previous write (INC #31) finishes. 

    Thus the cycle count is ~3x what you expect due to the pipeline stalls.

    Now if each instruction were writing to a *different* memory locations then it wouldn't matter and the read wouldn't have to wait. 

    One last thing, the write followed by read protection is also in place for the peripheral frames (any access - doesn't have to be the same location).  This is because a write to one register may change the contents of another. 

    Regards

    Lori

  • Thank you Lory.

    Your reply help me to understand the issue.