Compiler bug in passing var addresses before calling procedure ?

General discussion on mikroPascal PRO for PIC.
Post Reply
Author
Message
HoloLAB
Posts: 7
Joined: 03 Jun 2014 21:29

Compiler bug in passing var addresses before calling procedure ?

#1 Post by HoloLAB » 02 Jan 2023 20:22

First : Happy year++ ;)

Hi,
we are in a rush to deliver a product based on PIC18F66K80. My compiler rev is 7.6.0.
Sometimes some floating point calculation results are corrupted. Powering OFF/ON the target sometimes fix the pb, sometimes not...
Sometimes, adding some dummy instructions somewhere in the beginning of the code has temporarily fixed the pb but adding code fails again !

It looks like a typical RAM corruption problem (string not 0 terminated, buffer overflow, ...).
That's why I started digging into the assembly listing.

On the board there is a temperature and pressure sensor (Bosch BMP388). To get the real compensated pressure and temperature, you have to do some maths using floating point operations. The pb we have is a corrupted pressure, but returned temperature is always OK.

The procedure used to calculate temperature and pressure is the following one (for sake of clarity only parts of code are shown here) ;

Code: Select all

procedure BMP_GetData(var temperature, pressure:real);
var p_lin:real;
begin
    ...
    pressure := p_lin/100.0;	// p_lin is a partial data, local var
end;
   
Which is compiled into :

Code: Select all

;BMP388.mpas,442 :: 		pressure := p_lin/100.0;
0x26B0	0x0E00      	MOVLW       0
0x26B2	0x6E04      	MOVWF       R4 
0x26B4	0x0E00      	MOVLW       0
0x26B6	0x6E05      	MOVWF       R5 
0x26B8	0x0E48      	MOVLW       72
0x26BA	0x6E06      	MOVWF       R6 
0x26BC	0x0E85      	MOVLW       133
0x26BE	0x6E07      	MOVWF       R7 
0x26C0	0xF008ECE8  	CALL        _Div_32x32_FP, 0
0x26C4	0xFFE1C83F  	MOVFF       FARG_BMP_GetData_pressure, FSR1L
0x26C8	0xFFE2C840  	MOVFF       FARG_BMP_GetData_pressure+1, FSR1H
0x26CC	0xFFE6C000  	MOVFF       R0, POSTINC1
0x26D0	0xFFE6C001  	MOVFF       R1, POSTINC1
0x26D4	0xFFE6C002  	MOVFF       R2, POSTINC1
0x26D8	0xFFE6C003  	MOVFF       R3, POSTINC1
;BMP388.mpas,460 :: 		end;
L_end_BMP_GetData:
0x26DC	0x0012      	RETURN      0
; end of _BMP_GetData
This is a typical case of var passed by address. FSR1 is used here for indirect addressing to transfer the result of the division (R0 to R3) into the variable passed.
One can see that addresses $083D/$083E and $083F/$0840 are allocated by the compiler to store the address of the passed var :

Code: Select all

0x083D       [2]    FARG_OLED_DrawPixel_pos_x
0x083D       [2]    FARG_BMP_GetData_temperature                    <------ address allocated (2 bytes) to pass the address of passed TEMPERATURE
0x083D       [1]    FARG_OLED_SendData_cmd
0x083D       [4]    TMC_Home_dummyDat
0x083D       [4]    FARG_TMC_GoToPosition_position
0x083D       [1]    FARG_OLED_SendCommand_cmd
0x083D       [4]    FARG_floor_x
0x083D       [1]    FARG_UART_Write_data_
0x083D       [2]    FARG_LEDRGB_FillChannel2Buffer_color
0x083D       [4]    FARG_LongIntToByte_value
0x083D       [1]    LEDRGB_Show_i
0x083D       [2]    FARG_LEDRGB_FillChannel1Buffer_color
0x083F       [1]    LEDRGB_FillChannel2Buffer_i
0x083F       [1]    LEDRGB_FillChannel1Buffer_i
0x083F       [2]    FARG_BMP_GetData_pressure				<----- address allocated (2 bytes) to pass the address of passed PRESSURE
0x083F       [2]    FARG_OLED_DrawPixel_pos_y
0x0841       [6]    BMP_GetData_measurements
0x0841       [4]    floor_local_result
0x0841       [1]    FARG_OLED_DrawPixel_color
0x0841       [2]    FARG_LongIntToByte_byteArray
0x0845       [2]    floor_expon
A call of this procedure with two global real var gives that :

Code: Select all

;Init.mpas,104 :: 		BMP_GetData(gDumReal2,gDumReal1);
0x520C	0x0E96      	MOVLW       _gDumReal2
0x520E	0x0108      	MOVLB       8
0x5210	0x6F3D      	MOVWF       FARG_BMP_GetData_temperature, 1
0x5212	0x0E06      	MOVLW       hi_addr(_gDumReal2)
0x5214	0x6F3E      	MOVWF       FARG_BMP_GetData_temperature+1, 1
0x5216	0x0E00      	MOVLW       higher_addr(_gDumReal2)
0x5218	0x6F3F      	MOVWF       FARG_BMP_GetData_temperature+2, 1
0x521A	0x6F40      	MOVWF       FARG_BMP_GetData_temperature+3, 1
0x521C	0x0E8E      	MOVLW       _gDumReal1
0x521E	0x6F3F      	MOVWF       FARG_BMP_GetData_pressure, 1
0x5220	0x0E06      	MOVLW       hi_addr(_gDumReal1)
0x5222	0x6F40      	MOVWF       FARG_BMP_GetData_pressure+1, 1
0x5224	0x0E00      	MOVLW       higher_addr(_gDumReal1)
0x5226	0x6F41      	MOVWF       FARG_BMP_GetData_pressure+2, 1
0x5228	0x6F42      	MOVWF       FARG_BMP_GetData_pressure+3, 1
0x522A	0xF010EC4D  	CALL        _BMP_GetData, 0
With this global var allocation :

Code: Select all

0x068E       [4]    _gDumReal1
0x0692       [4]    _gAmbiantPressure
0x0696       [4]    _gDumReal2
As expected $0696 (address of gDumReal2) is stored into $083D/$083E (where procedure BMP_GetData is expecting the address of the temperature passed var).
Same for $068E stored into $083F/$0840.

But I do not understand why the compiler is passing the address of each var with 4 bytes (FARG_BMP_GetData_xxxx to FARG_BMP_GetData_xxxx+3)... 16 bit address should be enough for pointing a 3648 byte RAM.
This is erasing with 00s the 2 next RAM addesses, which is not a problem for gDumReal2, because it erases gDumreal1, but for dDumReal1, it is erasing (corrupting) another global var of the program...


Elsewhere in the code, the same procedure is called with a slight difference between the 2 passed var :
- gDumReal2 is a global var (in a unit called "Variables", used by main program)
- ch1press is a local var of the "CalibrationSequence()" procedure implemented in another unit used and called by the main program :

Code: Select all

procedure CalibrationSequence();
var ch1press,ch2press: real;
      calibOK, run, previousCalibOK : byte;
begin
    ...
    BMP_GetData(gDumReal2,ch1press);
    ...
end:

Which is compiled into :

Code: Select all

;Init.mpas,63 :: 		BMP_GetData(gDumReal2,ch1press);
0x5134	0x0E96      	MOVLW       _gDumReal2
0x5136	0x0108      	MOVLB       8
0x5138	0x6F3D      	MOVWF       FARG_BMP_GetData_temperature, 1
0x513A	0x0E06      	MOVLW       hi_addr(_gDumReal2)
0x513C	0x6F3E      	MOVWF       FARG_BMP_GetData_temperature+1, 1
0x513E	0x0E00      	MOVLW       higher_addr(_gDumReal2)
0x5140	0x6F3F      	MOVWF       FARG_BMP_GetData_temperature+2, 1
0x5142	0x6F40      	MOVWF       FARG_BMP_GetData_temperature+3, 1
0x5144	0x0EF2      	MOVLW       CalibrationSequence_ch1press
0x5146	0x6F3F      	MOVWF       FARG_BMP_GetData_pressure, 1
0x5148	0x0E07      	MOVLW       hi_addr(CalibrationSequence_ch1press)
0x514A	0x6F40      	MOVWF       FARG_BMP_GetData_pressure+1, 1
0x514C	0xF010EC4D  	CALL        _BMP_GetData, 0
Surprinsingly, address of ch1press is well passed with 16 bit before calling...

Conclusion: it seems that global and local var are not passed in the same way. And global var address is not passed as it should do.

This is certainly not the root cause of my problems, but to my (tired....) eyes it is a big potential cause of var corruption.

Thanks for your feedback !

janni
Posts: 5373
Joined: 18 Feb 2006 13:17
Contact:

Re: Compiler bug in passing var addresses before calling procedure ?

#2 Post by janni » 03 Jan 2023 15:42

Happy New Year :D
HoloLAB wrote:
02 Jan 2023 20:22
Conclusion: it seems that global and local var are not passed in the same way. And global var address is not passed as it should do.

This is certainly not the root cause of my problems, but to my (tired....) eyes it is a big potential cause of var corruption.
Your tired eyes are right, this is a bug with potential to disrupt memory adjacent to the parameters. As you noticed, it concerns only global variables of type real and the only solution is to implicitly use pointers, like

Code: Select all

procedure BMP_GetData(temperature, pressure: ^real);
var p_lin:real;
begin
    ...
    pressure^ := p_lin/100.0;	
end;

BMP_GetData(@gDumReal2,@ch1press);

HoloLAB
Posts: 7
Joined: 03 Jun 2014 21:29

Re: Compiler bug in passing var addresses before calling procedure ?

#3 Post by HoloLAB » 06 Jan 2023 09:46

Dear Janni,

thanks for the solution ! I had carefuly read all the documentation and bugs/quirks, but missed that information on global real...

We still have big problems with the system we are currently developping. Last was a SPI OLED display sometimes no more displaying or displaying strange hieroglyphs. It finally turned out to be a table read protection enabled on segment starting at $0800, and of course the char graphical definition was sometimes fully/partially placed into that segment....

Thanks again for all what you are doing here.

HoloLAB
Posts: 7
Joined: 03 Jun 2014 21:29

Re: Compiler bug in passing var addresses before calling procedure ?

#4 Post by HoloLAB » 06 Jan 2023 09:55

To Mikroe Team :

As a delphi programmer, I really love Pascal (and hate C...). As a hobbyist fond of microcontrollers, when MikroPascal went into my life in 2012, it really was an amazing opportunity.
Regarding the future of MikroPascal, last release was 4 years ago. And there are a lot of remaining bugs to fix. What is the roadmap for this tool ? Is it deprecated due to the new Necto solution ?
More globally, shall we start to move to C programming ?

Thanks.

HoloLAB
Posts: 7
Joined: 03 Jun 2014 21:29

Re: Compiler bug in passing var addresses before calling procedure ?

#5 Post by HoloLAB » 29 Jun 2023 09:33

Hi Mikroe Team,

Could you please answer to my question about the future of mikroPascal for PIC ?

IS IT A DEAD PRODUCT ?
SHALL WE SWITCH TO ANOTHER PRODUCT ?

Thanks.

Post Reply

Return to “mikroPascal PRO for PIC General”