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

trastikata

Quote from: PicNoob on Feb 20, 2025, 06:48 PMThe symptom is that ram byte at location 0x73 (sometimes based on program size it moves up or down in location) is changing when no assignment is made to them, when compiled in v4. The change happens when other activities in program execute and other unrelated ram bytes are changed. When compiled in v3.5 with zero program changes no such issue occurs. 

Unless the variable associated with RAM location 0x73 is fixed to that location with the directive At, then this changes nothing and as we said - this is normal and it is not a symptom of anything. So again, this is not the issue causing your program to behave differently.

Dompie

Do I understand correctly (without source I find it very difficult to follow) that the bootloader has been loaded and that another program has been loaded and executed and this other program (not the bootloader) changes addresses 73 and 74?

Johan

kcsl

Maybe I'm not understanding the initial issue, but it sounds like you believe a variable is changing it's value unexpectedly. You believe that something, possibly another variable, is overwriting all or part of the first variable, meaning that the two variables are affectively overlapping each other, trying to share the same memory addresses and so interfering with each other ?
There's no room for optimism in software or hardware engineering.

PicNoob

Quote from: kcsl on Feb 20, 2025, 08:09 PMMaybe I'm not understanding the initial issue, but it sounds like you believe a variable is changing it's value unexpectedly. You believe that something, possibly another variable, is overwriting all or part of the first variable, meaning that the two variables are affectively overlapping each other, trying to share the same memory addresses and so interfering with each other ?

That is my thought yes. When compiled in v4 the variable changes despite all references to changing it being commented out.

PicNoob

#24
Quote from: trastikata on Feb 20, 2025, 06:54 PM
Quote from: PicNoob on Feb 20, 2025, 06:48 PMThe symptom is that ram byte at location 0x73 (sometimes based on program size it moves up or down in location) is changing when no assignment is made to them, when compiled in v4. The change happens when other activities in program execute and other unrelated ram bytes are changed. When compiled in v3.5 with zero program changes no such issue occurs. 

Unless the variable associated with RAM location 0x73 is fixed to that location with the directive At, then this changes nothing and as we said - this is normal and it is not a symptom of anything. So again, this is not the issue causing your program to behave differently.

Maybe I am understanding the assembly incorrectly then. I thought that the compiler assigns memory locations at compile time resulting in fixed locations in the assembly file.

So in the assembly file I have this in the definitions. I cut it short but the variable with the issue is calc_torque, which is a word, so we have calc_torque and calc_torqueH.

I'm not sure what the difference between "standard variables" and "start of bank0" is referring to but as I mentioned assembly is not really my world. I presume standard variables are some area of ram before bank0? Space set aside for system that is unused? In any event are you saying that although calc_torque starts at 0x77 in bank0 here, that it will move around within the program? If so that makes finding the problem much more difficult. :(

Quote; STANDARD VARIABLES
tmap_in equ 0x3E
tmap_inH equ 0x3F
fp_in equ 0x40
fp_inH equ 0x41
map_in equ 0x42
map_inH equ 0x43
tmap_out equ 0x44
tmap_outH equ 0x45
fp_out equ 0x46
fp_outH equ 0x47
map_out equ 0x48
map_outH equ 0x49
rpm equ 0x4A
rpmH equ 0x4B
tempW equ 0x4C
tempWH equ 0x4D
tempW2 equ 0x4E
tempW2H equ 0x4F
tempW3 equ 0x50
tempW3H equ 0x51
index equ 0x52
index_usb equ 0x53
output_count equ 0x54
output_countH equ 0x55
boost_zero equ 0x56
boost_zeroH equ 0x57
n1MINRPM equ 0x58
n1MINRPMH equ 0x59
n1MAXRPM equ 0x5A
n1MAXRPMH equ 0x5B
dutycycle equ 0x5C
dutycycleH equ 0x5D
CANprescale equ 0x5E
CANprescaleH equ 0x5F
; START OF RAM BANK 0
CANprescale2 equ 0x60
CANprescale2H equ 0x61
USBOUT4 equ 0x62
USBOUT4H equ 0x63
shiftRED equ 0x64
shiftREDH equ 0x65
shiftRED2 equ 0x66
shiftRED2H equ 0x67
meth_in equ 0x68
meth_inH equ 0x69
boost_zero_ECU equ 0x6A
boost_zero_ECUH equ 0x6B
boost_pivot equ 0x6C
boost_pivotH equ 0x6D
boost_pivot_map equ 0x6E
boost_pivot_mapH equ 0x6F
USBOUT8 equ 0x70
USBOUT8H equ 0x71
e85_analog_in equ 0x72
e85_analog_inH equ 0x73
throttlePOS equ 0x74
oilTEMP equ 0x75
oilTEMPH equ 0x76
calc_torque equ 0x77
calc_torqueH equ 0x78
waterTEMP equ 0x79
waterTEMPH equ 0x7A
timing equ 0x7B
timingH equ 0x7C
boost_zero_map equ 0x7D
boost_zero_mapH equ 0x7E
ewg_in equ 0x7F
ewg_inH equ 0x80
ewg_out equ 0x81
ewg_outH equ 0x82
data_checksum equ 0x83
rpm_last equ 0x84
rpm_lastH equ 0x85
methAVG equ 0x86
methAVGH equ 0x87
fpAVG equ 0x88
fpAVGH equ 0x89
misc_in equ 0x8A
misc_inH equ 0x8B
exp1 equ 0x8C
exp1H equ 0x8D
EGTtimer equ 0x8E
EGTtimerH equ 0x8F
storage_address equ 0x90
storage_addressH equ 0x91
storage_addressHH equ 0x92
storage_addressHHH equ 0x93
sent_in equ 0x94
sent_inH equ 0x95
sent_in_temp equ 0x96
sent_in_tempH equ 0x97
sent_in_error equ 0x98
sent_out equ 0x99
sent_outH equ 0x9A
sent_out_temp equ 0x9B
sent_out_tempH equ 0x9C
maf_in equ 0x9D
maf_inH equ 0x9E
maf_out equ 0x9F
maf_outH equ 0xA0
solenoid_out equ 0xA1

trastikata

Quote from: PicNoob on Feb 20, 2025, 09:23 PMMaybe I am understanding the assembly incorrectly then. I thought that the compiler assigns memory locations at compile time resulting in fixed locations in the assembly file.

I am afraid you are getting completely confused by the insufficient knowledge (please don't get offended) of the Assembler listing.

A variable or variable name is just an alias for given memory location, for example "MyVariable" means memory location 0x35 - that location is being assigned at compile time and for most of the common operations it doesn't matter what memory location is being assigned. The compiler knows that values being read from or to "MyVariable" means actually reading and writing from or to memory location 0x35.   

Anyway if you don't want to share any program code I think you should focus your effort on describing what actually is happening. For example:

- You have variable called "MyVariable"
- You assign value to that variable at compile time, for example "Dim MyVariable as Byte = 55"
- You do nothing with "MyVariable" but when you try to display it (serial port or some display) it appears to have different value than per-assigned i.e. in case of this example, the value is different from 55

Did I understand the problem correctly?

PicNoob

Quote from: trastikata on Feb 20, 2025, 09:43 PM
Quote from: PicNoob on Feb 20, 2025, 09:23 PMMaybe I am understanding the assembly incorrectly then. I thought that the compiler assigns memory locations at compile time resulting in fixed locations in the assembly file.

I am afraid you are getting completely confused by the insufficient knowledge (please don't get offended) of the Assembler listing.

A variable or variable name is just an alias for given memory location, for example "MyVariable" means memory location 0x35 - that location is being assigned at compile time and for most of the common operations it doesn't matter what memory location is being assigned. The compiler knows that values being read from or to "MyVariable" means actually reading and writing from or to memory location 0x35.   

Anyway if you don't want to share any program code I think you should focus your effort on describing what actually is happening. For example:

- You have variable called "MyVariable"
- You assign value to that variable at compile time, for example "Dim MyVariable as Byte = 55"
- You do nothing with "MyVariable" but when you try to display it (serial port or some display) it appears to have different value than per-assigned i.e. in case of this example, the value is different from 55

Did I understand the problem correctly?

Yes that is correct. When compiled in v4 I can see the variable changing values in my serial interface, when there is no explanation or path for those values to change. The same program compiled in v3.5 does not have this bug. I don't mind sharing some code but I don't believe it will move the ball forward as its a large complicated program and I have been unable to recreate the issue in a small program.

My theory for the issue is that the v4 compiler is doubling up or not properly managing a RAM address for the specific variable, which is why I dove into the assembly file in the first place.

So my theory is that for example if calc_torqueH is mapped to ram 0x78 at compile time, somewhere in assembly I should find some other reference writing or overflowing into ram address 0x78. 
 

 

PicNoob

Quote from: Dompie on Feb 20, 2025, 07:03 PMDo I understand correctly (without source I find it very difficult to follow) that the bootloader has been loaded and that another program has been loaded and executed and this other program (not the bootloader) changes addresses 73 and 74?

Johan

Unfortunately we went off on some tangents here. But the basic issue is that a specific ram address (it moves around within a small range based on program size) is getting corrupted when compiled in v4 but not when compiled in v3.5, and I'm trying to find some way to identify the cause in the assembly file to run it up the flagpole for a repair. Or find some other explanation for the cause like an array or stack overwrite or something, which I haven't been able to find, and which should be the same in either compiler.

trastikata

Quote from: PicNoob on Feb 20, 2025, 10:55 PMYes that is correct. When compiled in v4 I can see the variable changing values in my serial interface, when there is no explanation or path for those values to change. The same program compiled in v3.5 does not have this bug. I don't mind sharing some code...

For the moment please forget about Assembler, I repeat, from what you are writing here, it looks like due to lack of sufficient knowledge of the Assembler, you are getting more confused by trying to give sense to things. 

Please upload the entire program file and indicate which variable is changing values with no obvious reason.

PicNoob

Quote from: trastikata on Feb 20, 2025, 11:08 PM
Quote from: PicNoob on Feb 20, 2025, 10:55 PMYes that is correct. When compiled in v4 I can see the variable changing values in my serial interface, when there is no explanation or path for those values to change. The same program compiled in v3.5 does not have this bug. I don't mind sharing some code...

For the moment please forget about Assembler, I repeat, from what you are writing here, it looks like due to lack of sufficient knowledge of the Assembler, you are getting more confused by trying to give sense to things. 

Please upload the entire program file and indicate which variable is changing values with no obvious reason.

I can't post it but let me know your email and I can email it over!

PicNoob

#30
I found another interesting item that might be related. The code when compiled on v4 executes around 15% slower than when compiled on v3.5. So maybe whatever is causing this variable issue is also slowing it down?

Made some progress last night... Traced the issue down to the boot loader. If its compiled in v3.5 the main program compiled in v4 doesn't have the bug. But if boot loader is compiled in v4 then the bug crops up if main program is also compiled in v4. Has to be some default compiler change or something. I'll see if I can find notes on things that changed between 3.5 and the latest.

 

PicNoob

#31
Thanks to the hard work of @trastikata I believe we found the issue. It appears that doubling up on the context saves due to a misplaced redirect was causing the issue in v4 but for some reason not v3.5. Since correcting it I haven't been able to recreate the symptoms.

In my bootloader I originally had the redirect like this:

 
Quote'****************************************************************       
'* Interrupt Service Routine Inside Bootloader
'****************************************************************
HIGH_INTERRUPT_ROUTINE:

Context Save

    If bootloader_active = 1 Then
        GoTo vector_remap
    EndIf


But changing it to this I believe resolved the issue:

 
Quote'****************************************************************       
'* Interrupt Service Routine Inside Bootloader
'****************************************************************
HIGH_INTERRUPT_ROUTINE:



    If bootloader_active = 1 Then
        GoTo vector_remap
    EndIf

   Context Save


   
       

top204

Remember, you cannot just jump out of an interrupt handler's routine to another section of code!

The compiler keeps track of the high level code used between its Interrupt Label, and the Context Save and Context Restore directives. So it can monitor whatever compiler system variables or certain SFRs are used within that section and save them in RAM, for later restoring with Context Restore.

So if a jump out of the routine is made, the compiler can no longer keep track of variables and it will cause all sorts of subtle anomalies in the program's operation, because some variables and SFRs will be over-written because they have not been restored when the interrupt ends.

I can see I am going to have to be a lot more strict with the compiler's error, and syntax, and layout monitoring, in later compiler updates, because I have made the compilers too flexible for their own good. :-)

flosigud

This is a user problem, no need to do anything with the compilers. The compilers are maybe not perfect, but close.

kcsl

Les, just to clarify when you say "you cannot just jump out of an interrupt handler's routine to another section of code" do you mean that calling procedures that return to their caller is fine, but using GOTO for example to exit the ISR (effectively making it re-entrant) is problematic?
There's no room for optimism in software or hardware engineering.

John Lawton

Dunno about making it re-entrant.

My simple understanding is that if you exit an ISR routine via a GOTO and don't return via another GOTO then you'll likely regret it as you haven't executed the Context Restore command.

OTOH a subroutine call from within the ISR should work okay, but I don't consider it good practice to call subroutines from an ISR. I try to keep an ISR as simple and fast as possible, so better to keep all the code in the ISR itself in my view. Oftentimes (polled) code in the main loop can do these jobs better than doing it in the ISR.

John

top204

The compiler keeps track of its system variables used between Context Save and Context Restore, and the SFRs used by any commands within the interrupt handler, so it knows what variables and SFRs to save before the interrupt's code runs, and restores them back to how they were before the interrupt code was called, after the interrupt is finished. Otherwise, variables and certain SFRs would get over-written.

The compiler creates a block of RAM that they are all saved too, named "_High__Context_Store", and "_Low__Context_Store" for Low priority interrupts on 18F devices.

However, if a Goto or Gosub command is used within the interrupt handler's code.... All of a sudden a new section of code is running that is not between Context Save and Context Restore, but is still using system variables and SFRs, but the compiler has now lost track of them and cannot see what is being used. The compiler cannot track every single Goto or Gosub, because where would they start and end?

A procedure call has some protection, and, in the Positron8 compiler only, I have recently added a mechanism that saves/restores the variables used within a procedue if it is called from within an interrupt handler, because the compiler knows where the procedure starts and where it ends, and the code within the procedure is a known quantity, with its own structs within a TList, so everything about it is known, and a flag is set if the variables within the procedure also need saving/restoring because it was called from within an Interrupt handler section, and any procedure calls made from within the initial procedure also have their flag set to save variables and SFRs. But it is still in Beta stage.

I am investigating how to do this type of mechanism on the Positron16 compiler, but with multi-interrupt vectors on the 16-bit devices, it is not as straightforward as it is with the 8-bit devices. So on the Positron16 compiler, no Goto, Gosub or procedure calls should be made from with an interrupt handler.

I have just added an error and a warning if a Gosub is used within an interrupt handler, or a Goto is used.

A Gosub will cause an error: "A 'Gosub' command cannot be issued from within an Interrupt Handler routine, otherwise the compiler will loose track of variables used within the interrupt"

A Goto will cause a warning: "Make sure the 'Goto' command is jumping to a label within the Interrupt Handler routine's code, otherwise the compiler will loose track of variables used within the interrupt"

These will be in the next compiler update, and I will also be adding them to the Positron16 compiler.


trastikata

Hi Les, so as long as the code section where the GoTo and GoSub are pointing to, remain within the Context Save / Context Restore, the program flow is safe?

top204

Quoteso as long as the code section where the GoTo and GoSub are pointing to, remain within the Context Save / Context Restore, the program flow is safe?

Yes, because they still lie between the Context Save and Context Restore directives, but as of the next update, a Gosub will give an error, and not be allowed.

A Goto will give a warning, because a Goto is sometimes needed within code to jump over sections, but a Gosub is never needed within it, so will error.

John Lawton

Quote from: top204 on Feb 27, 2025, 11:03 AMA Goto will give a warning, because a Goto is sometimes needed within code to jump over sections

Les, to clarify, as perhaps my understanding given above is wrong. If a GOTO in an ISR is executed to any bit of code outside that ISR, even if, in that bit of code, it is ended by a GOTO back into the ISR, that would still be problematic?

I think I've done that before...

John