News:

;) This forum is the property of Proton software developers

Main Menu

How many cycles?

Started by See_Mos, Aug 03, 2022, 05:32 PM

Previous topic - Next topic

See_Mos

Help please.

How many clocks cycles does it take to call a procedure with no parameters or with one byte passed to the procedure?

top204

#1
Unfortunately See_mos, that is like asking how long is a piece of string. :-)

It depends on the device type, how far away the procedure is from the item calling it, how large is the parameter variable, what is being loaded into the parameter variable, what RAM bank is the parameter in, if the parameter variable is crossing RAM banks, what code page is the procedure in (with 14-bit core devices). The list goes on....

The compiler does not produce "ready made code", and it acts dynamically as much as it can, so it optimises the assembler code wherever possible as it is creating it, with some of the optimisations being so obscure they are not actually noticed, but make a difference in a larger program, or a section of code that needs to be efficient.

For example, it will be seen...

For: Print "HELLO"

The assembler code will be (with added comments):

Movlw 72       ; Load the value for character "H" in WREG
Call __print_  ; Display the contents of WREG
Movlw 69       ; Load the value for character "E" in WREG
Call __print_  ; Display the contents of WREG
Movlw 76       ; Load the value for character "L" in WREG
Call __print_  ; Display the contents of WREG
Call __print_  ; Display the contents of WREG
Movlw 79       ; Load the value for character "O" in WREG
Call __print_  ; Display the contents of WREG

But. Hold on.... The above assembler code is only sending one "L" character (76), so how can it display "HELLO"?. Because the __print_, library, subroutine stores and returns the contents of the WREG SFR that was sent to it and the compiler monitors the value held in WREG while it is compiling the code, so it knows when it can be re-used and when to reset it so it will be loaded with a fresh value. The same happens when loading into String variables and arrays and other variables and some other library subroutines that are suitable for it.

So when loading a multi-byte variable with a value that has adjacent parts containing the same value. For example, for a Word variable:

MyWord = $AAAA

The assembler code will be:

Movlw 170
Movwf MyWord
Movwf MyWordH

Because the WREG is monitored while the program is being compiled, it knows when it can use the contents of WREG again without having to use a new Movlw mnemonic to load it. But it does not take it for granted, and if it is not sure, it will reset the flag so that WREG is re-loaded. This mainly happens with 14-bit core devices because of their fragmented RAM.

So... For a standard procedure on an 18F device that is not close to the item calling it, and the parameter is in Access RAM, it uses a Call mnemonic, or an rcall mnemonic if the procedure is close to the item calling it. And if the parameter is a Byte being loaded with a constant value it will use the Clrf mnemonic, or the Setf mnemonic of the Movlw/Movwf mnemonics depending on the value passed to it. Then it will use the Return mnemonic, and reset the RAM banks before the Return if any of the code within the procedure is using variables in differing RAM banks. Or a Goto or Bra mnemonic to a subroutine instead of the Return, if there is a subroutine call or procedure call at the very end of the procedure, so the subroutine jumped too will perform the Return.

The previous paragraph could be repeated hundreds of times with differing assembler mnemonics and for differing scenarios of what and where and who, and that is why the compiler produces such tight and fast assembler code that allows small devices to sometimes do things they should not actually be able to do in a high level language. :-)





RGV250

Hi,
I don't know if it will help your situation but this is a routine I used to use many years ago. Not my code but cannot remember who actually did post it.

Include "PROTON18_G20.INT" 'Proton 20MHz Graphics LCD
Dim TIMER1 As TMR1L.Word 'See help file
'DIM X AS FLOAT
'DIM Y AS FLOAT 'Dim some FLOATS
'DIM Z AS FLOAT

DelayMS 500 'Give PIC a chance to wake-up

Cls 'Clear the GLCD

'X = 1234.321 'Load 1234.321 into X FLOAT
'Y = 3.33 'Load 3.33 into Y FLOAT
Dim pressure As Float

Clear TIMER1 'Clear TIMER1
'#########################
T1CON = %00000001 'Enable the Timer

'Z = X * Y 'Code to calculate
pressure = (1023 * 0.04741) - 13.217

T1CON = %00000000 'Stop the Timer
'#########################

Print At 0,0,"cycles ",Dec TIMER1 'Print out the number of Cycles
Print At 2,0,"ANSWER ",Dec pressure 'Print out Answer
End

Include "FONT.INC" 'Include the font for GLCD
'--------------------------------------------------------------------------------
'Put the code you want to calculate the number of cycles
'between Enable Timer---Stop Timer

'Remember Timer1 on the 16F877 is 16 bits
'so 65535 is the max you can count before Timer overflows.

'In the above example 1234.321 is multiplied by 3.33
'Which gives an answer of 4110.289 and took 480 Cycles...


Bob

See_Mos

#3
Thanks Les, I should have mentioned that the device is an 18F25K22 and there are only two variables and quite a few constants.   So far the compiled code is only around 4K.

 I need to do some research, we have been isolated from assembler level coding for so many years as a result of your excellent work that we have forgotten much of the basics.

Unfortunately my old head is struggling somewhat so I will probably have to ask more questions about thing that I have forgotten.

Bob, thanks for reminding me of that routine.  I will see if it helps

top204

#4
Bob... If you want to find out how long a particular sequence of code takes for a standard mechanism, the easy way is to run it in the Isis simulator and add breaks to the source code listing.

Even if the particular device is not supported in the simulator, use another device of the same family. At the bottom of the simulator's screen it will show how long it took for two break points to operate.

If you do not have the Proteus package, and I do not blame you for that because of its very stupidly high price, there is a demo version of Proteus. The demo is rather useless for any serious testing of code or the application itself, but you can do simple tests with it. There are also, countelss versions of Proteus on the internet that "normal" people who do not have money to waste can use.

I use this feature all the time to see if the code changes I make are worth the effort. :-) And to time interrupts in programs.

See_Mos

The code is now at 5.5k and I have two more procedures to add that will take it over the 8k boundary of the 25K22.  I tried to get hold of 18F26K22 but Farnell and R.S. Are quoting next year for delivery.

I will give Proteus a try, my licence ran out at beta 8.

I will look to see if I can find an alternative device, I  only need 64Mhz, two ports and no peripherals.

top204

See_Mos... The PIC18F25K22 device has 32K (32768 bytes) of flash memory.

It used to be that the licence expiring in Proteus meant that no updates could be made to it, but it still ran OK. Have they also moved to "Rented" software?

JonW

Maybe I am old school from Asm days but to time anything I always use an i/o and flip a pin state and use a scope and simple math to deduce timebases.  I use pin states all the time to flag positions or states in the code flow as these can be traced easily these days in low cost digital scopes or DSA's.  Plus you can process millions of instructions to see how and where errors creep into code flow without stepping through instructions


JonW

#8
PIcs are hard to get hold of at the moment.  If you based in the UK based I may have parts in the lab I can share 

JonW

Quote from: top204 on Aug 07, 2022, 07:52 PMSee_Mos... The PIC18F25K22 device has 32K (32768 bytes) of flash memory.

It used to be that the licence expiring in Proteus meant that no updates could be made to it, but it still ran OK. Have they also moved to "Rented" software?


It should still run, their licence base is perpetual so you stay at the revision when the USC   terminates.

See_Mos

Yes, Proteus does still run OK but I don't use it very often because I am never sure that problems are with my coding or with Proteus so I prefer to use real hardware.

I am also using a pin to bracket sections of code and look at the timing on a 25Mhz Picoscope but together with the slow rise and fall times of the PIC it is not so easy to measure values such as 27.3uS, 4.7uS, or as close as I can get.

I will reveal the project once I have it stable.