News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

RAM issue on specific variable v3.5.0.6 vs v4.0.4.8

Started by PicNoob, Feb 16, 2025, 09:25 PM

Previous topic - Next topic

top204

If a routine is jumped too from within the code of the Interrupt Handler, none of its system variables or SFRs will be saved, because the compiler has now lost track of where it is, because the compiler does not jump around like the program does, it compiles from start to finish, line per line.

For example, the code snippet below shows what I mean:

'----------------------------------------------------------------------------
MyRoutine:
    Byteout = (Byteout / 234) + (Byteout * 5)
    GoTo Back_Where_I_Came_From
      
'----------------------------------------------------------------------------
ISR_Handler:
    Context Save

    GoTo MyRoutine
Back_Where_I_Came_From:

    Context Restore

See how the Goto within the ISR_Handler is jumping to the MyRoutine label, and within the MyRoutine's code, there are system variables used for the expression. But the compiler has lost track, because MyRoutine is not within the Context directives, so it cannot know that it needs to save because it is in an interrupt, because it is 'not' in an interrupt, and is just a label in the flat program with some code following it.

So the assembler code is:

;---------------------------------------------
; HIGH PRIORITY INTERRUPT HANDLER
ISR_Handler
F1_000093 equ $ ; in [TEST_18F25K20.BAS] Context Save
    movlb 0x00
F1_000095 equ $ ; in [TEST_18F25K20.BAS] goto MyRoutine
    bra MyRoutine
Back_Where_I_Came_From
F1_000098 equ $ ; in [TEST_18F25K20.BAS] Context Restore
    retfie 1

Nothing saved or restored, just the jump to the label, and whatever is used in the label's code will be over-writing background code's RAM and SFRs.

However, if the expression is placed within the interrupt handler, it all changes:

'----------------------------------------------------------------------------
ISR_Handler:
    Context Save

    Byteout = (Byteout / 234) + (Byteout * 5)

    Context Restore


And the compiler knows that things need saving/restoring, so it produces the 'edited' assembler code below:

; HIGH PRIORITY INTERRUPT CONTEXT STORAGE
_High__Context_Store equ 0x1A
variable _High__Context_Store_0=0x1A,_High__Context_Store_1=0x1B,_High__Context_Store_2=0x1C,_High__Context_Store_3=0x1D
variable _High__Context_Store_4=0x1E,_High__Context_Store_5=0x1F,_High__Context_Store_6=0x20,_High__Context_Store_7=0x21
variable _High__Context_Store_8=0x22,_High__Context_Store_9=0x23,_High__Context_Store_10=0x24,_High__Context_Store_11=0x25

;---------------------------------------------
; HIGH PRIORITY INTERRUPT HANDLER
ISR_Handler
F1_000093 equ $ ; in [TEST_18F25K20.BAS] Context Save
    movlb 0x00
    movff PP0,_High__Context_Store_0
    movff PP0H,_High__Context_Store_1
    movff PP1,_High__Context_Store_2
    movff PP1H,_High__Context_Store_3
    movff PP2,_High__Context_Store_4
    movff PP2H,_High__Context_Store_5
    movff PP7,_High__Context_Store_6
    movff PP7H,_High__Context_Store_7
    movff PP8,_High__Context_Store_8
    movff PP8H,_High__Context_Store_9
    movff PRODH,_High__Context_Store_10
    movff PRODL,_High__Context_Store_11
F1_000095 equ $ ; in [TEST_18F25K20.BAS] Byteout = (Byteout / 234) + (Byteout * 5)
    clrf PP7H,0
    movff Byteout,PP7
    movff PP7H,PP0H
    movff PP7,PP0
    clrf PP1H,0
    movlw 234
    movwf PP1,0
    rcall __divide_u1616_
    movwf PP7,0
    movff PP0H,PP7H
    clrf PP8H,0
    movff Byteout,PP8
    movf PP8H,W,0
    mullw 5
    movff PRODL,PP8H
    movf PP8,W,0
    mullw 5
    movff PRODL,PP8
    movf PRODH,W,0
    addwf PP8H,F,0
    movf PP7,W,0
    addwf PP8,W,0
    movwf Byteout,0
F1_000097 equ $ ; in [TEST_18F25K20.BAS] Context Restore
    movff _High__Context_Store_0,PP0
    movff _High__Context_Store_1,PP0H
    movff _High__Context_Store_2,PP1
    movff _High__Context_Store_3,PP1H
    movff _High__Context_Store_4,PP2
    movff _High__Context_Store_5,PP2H
    movff _High__Context_Store_6,PP7
    movff _High__Context_Store_7,PP7H
    movff _High__Context_Store_8,PP8
    movff _High__Context_Store_9,PP8H
    movff _High__Context_Store_10,PRODH
    movff _High__Context_Store_11,PRODL
    retfie 1

Which includes the compiler system variables used in the expression, and the divide library routine as well.

top204

As a follow on to the post above...

However, with the 8-bit compiler only, there is an 'unofficial' way of making a section of code save its variables and SFRs, as though it was part of the interrupt. :-)

It is a fall back to the mechanism I created at the very beginning of the compiler saving/restoring variables and SFRs within an interrupt, that I never got rid of because it was handy to have. Wow! That was such a long time ago!

They are:

Declare High_Int_Sub_Start
Declare High_Int_Sub_End


and

Declare Low_Int_Sub_Start
Declare Low_Int_Sub_End


So if a section of code is wrapped with one of the above Declare pairs, the compiler knows that, that section of code is also part of an interrupt. For example:

'----------------------------------------------------------------------------
MyRoutine:
Declare High_Int_Sub_Start                      ' Tell the compiler that the next codes are part of a high level interrupt
    Byteout = (Byteout / 234) + (Byteout * 5)
Declare High_Int_Sub_End                        ' Tell the compiler that the following codes are not part of a high level interrupt
    GoTo Back_Where_I_Came_From
     
'----------------------------------------------------------------------------
ISR_Handler:
    Context Save

    GoTo MyRoutine
Back_Where_I_Came_From:

    Context Restore

And the assembler code produced, 'again editied', is:

; HIGH PRIORITY INTERRUPT CONTEXT STORAGE
_High__Context_Store equ 0x1A
variable _High__Context_Store_0=0x1A,_High__Context_Store_1=0x1B,_High__Context_Store_2=0x1C,_High__Context_Store_3=0x1D
variable _High__Context_Store_4=0x1E,_High__Context_Store_5=0x1F,_High__Context_Store_6=0x20,_High__Context_Store_7=0x21
variable _High__Context_Store_8=0x22,_High__Context_Store_9=0x23,_High__Context_Store_10=0x24,_High__Context_Store_11=0x25

;---------------------------------------------
; HIGH PRIORITY INTERRUPT HANDLER
ISR_Handler
F1_000096 equ $ ; in [TEST_18F25K20.BAS] Context Save
    movlb 0x00
    movff PP0,_High__Context_Store_0
    movff PP0H,_High__Context_Store_1
    movff PP1,_High__Context_Store_2
    movff PP1H,_High__Context_Store_3
    movff PP2,_High__Context_Store_4
    movff PP2H,_High__Context_Store_5
    movff PP7,_High__Context_Store_6
    movff PP7H,_High__Context_Store_7
    movff PP8,_High__Context_Store_8
    movff PP8H,_High__Context_Store_9
    movff PRODH,_High__Context_Store_10
    movff PRODL,_High__Context_Store_11
F1_000098 equ $ ; in [TEST_18F25K20.BAS] goto MyRoutine
    bra MyRoutine
Back_Where_I_Came_From
F1_000101 equ $ ; in [TEST_18F25K20.BAS] Context Restore
    movff _High__Context_Store_0,PP0
    movff _High__Context_Store_1,PP0H
    movff _High__Context_Store_2,PP1
    movff _High__Context_Store_3,PP1H
    movff _High__Context_Store_4,PP2
    movff _High__Context_Store_5,PP2H
    movff _High__Context_Store_6,PP7
    movff _High__Context_Store_7,PP7H
    movff _High__Context_Store_8,PP8
    movff _High__Context_Store_9,PP8H
    movff _High__Context_Store_10,PRODH
    movff _High__Context_Store_11,PRODL
    retfie 1

See how the interrupt is saving/restoring the variables used in the MyRoutine section, because the code following MyRoutine were wrapped in flags that told the compiler what was happening. This was the only method I could use to make a, then, 'flat' language more flexible with interrupts.

The Declares can be used multiple times within a program listing, signalling that sections are also part of an interrupt, But be careful, because a lot of RAM will need to be saved/restored if too many are used, and this will slow things down, and use up lots of RAM.


Remember, this is very unofficial and will work, but is not actually part of the 8-bit compiler's language. It's a one for a user's notebook of "things that might help, when I know what I am doing". :-)

John Lawton

Quote from: John Lawton on Feb 27, 2025, 12:52 PMI think I've done that before...

Well I guess I was lucky.

Thanks for the detailed explanation Les.

John

Frizie

I always keep the interrupt handler as short as possible and have (so far) never needed GOTOs inside the handler.
Often I set a global bit as a result that is determined inside the handler.
By polling this kind of bit(s) in the main loop, the corresponding execution is then processed further in the main loop.
Ohm sweet Ohm | www.picbasic.nl

PicNoob

Quote from: flosigud on Feb 26, 2025, 09:31 PMThis is a user problem, no need to do anything with the compilers. The compilers are maybe not perfect, but close.

Right I'm not blaming the compiler for my obvious oversight. :)

JonW

Les, you said you would add a catch error if gosub is used in the ISR and presume this will cause compilation failures; however, will this be ignored if the above Declares are used?  I am asking for other users, as this is a little unclear (I never call from within any ISR).


top204

A good point Jon. An error would make previous programs that work OK, fail.

So I have made a Gosub within an ISR handler a Warning, just as I have with Goto, so they can be disabled in a block of code by using the Declare Warnings = On or Off, but the compiler cannot be put to blame, because it told the user something is not quite right, but it will not fail the program with an error. :-)

The Declare Warnings and Declare Hints directives can be enabled and disabled throughout a program listing, for sections of code that a user knows is correct, but the compiler is not sure about, or informing the user that something could go wrong.

This means a routine will work if the Declare High_Int_Sub_Start and Declare High_Int_Sub_End or the Declare Low_Int_Sub_Start and Declare Low_Int_Sub_End are used with a program's listing.

Many thanks for that pointer Jon. It is always better to have a third party to point to bias' that the author/creator did not think of or see.