CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Problem with simple subtraction operator in if-statement

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

Problem with simple subtraction operator in if-statement
PostPosted: Wed Nov 25, 2009 3:33 pm     Reply with quote

Hi,

I was writing some code for PIC10F222 and came across this problem.

I was trying to subtract a variable from a static value before a comparison in an if-statement.
Code:

void main()
{
   int8 test1;
   int8 test2;
   int8 test3;

   test1 = 100;
   test2 = 100;
   test3 = 1;

   if(test1 > (100-1))
   {
      GP0 = 1;
   }
   else
   {
      GP0 = 0;
   }
}

The above code will put GP0 high. But if I replace (100-1) with (100-test3) GP0 will not be put high:
Code:

void main()
{
   int8 test1;
   int8 test2;
   int8 test3;

   test1 = 100;
   test2 = 100;
   test3 = 1;

   if(test1 > (100-test3))
   {
      GP0 = 1;
   }
   else
   {
      GP0 = 0;
   }
}

Did I do something wrong here? I guess the compiler will calculate (100-1) to be 99 and just insert this value in the code. But since test3 is 1 and 100-1 is 99, the result should be the same, right?

I'm using version 4.093.

Please help Very Happy
Ttelmah
Guest







PostPosted: Wed Nov 25, 2009 3:48 pm     Reply with quote

Not quite.

First, you need to have a while....true or similar at the end of your code to prevent the code dropping off the end.

As it stands, in the first case, the compiler will 'optimise' the test away, since the values are constants, and just insert the single line, setting GP0.
In the second, the lines can't be optimised away, since variables are being used, and these might be changed by something else. The test should evaluate to the same result, but the timing will be fractionally different.

Now, what you show shouldn't work at all, since you are not showing the TRIS being changed to make the pin an output, and are accessing the pin directly, bypassing the compiler's output functions.
I suspect if you avoid the drop off the end, and use the standard functions, it'll work fine:
Code:

void main()
{
   int8 test1;
   int8 test2;
   int8 test3;

   test1 = 100;
   test2 = 100;
   test3 = 1;

   if(test1 > (100-test3))
   {
      output_high(PIN_B0);
   }
   else
   {
      output_low(PIN_B0);
   }
   while (TRUE);
}


Best Wishes
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Wed Nov 25, 2009 3:56 pm     Reply with quote

Well, I must have trimmed my code too much then. Full .c file:

Code:
#include "test.h"

void main()
{
   int8 test1;
   int8 test2;
   int8 test3;

   ANS1 = 1; // GP1/AN1 configured for analog input
   ANS0 = 0; // GP0/AN0 configured as digital I/O
   
   set_tris_b(0b11111010); // Set pin directions (GP0, GP2 = Output --- GP1, GP3 = Input)
   GPIO = 0;               // Reset all pins to low


   test1 = 100;
   test2 = 100;
   test3 = 1;

   if(test1 > (100-test3))
   {
      GP0 = 1;
   }
   else
   {
      GP0 = 0;
   }
   while(1);
}


Full .h file:

Code:
#include <10F222.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOMCPU                   //Master Clear Pull-up disabled
#FUSES IOSC8                    //INTOSC speed 8MHz

#use delay(clock=8000000)
#use fast_io(b)

#use rs232(baud=2400, xmit=PIN_B2)

#byte GPIO = 0x06
#bit GP0   = GPIO.0
#bit GP1   = GPIO.1
#bit GP2   = GPIO.2
#bit GP3   = GPIO.3

#byte TMR0 = 0x01

#byte ADCON0 = 0x07 // A/D CONVERTER 0 REGISTER
#bit ANS1    = ADCON0.7 // ADC Analog Input Pin Select bit
#bit ANS0    = ADCON0.6 // ADC Analog Input Pin Select bit
//#bit 5: Unimplemented: Read as 0
//#bit 4: Unimplemented: Read as 0
#bit CHS1    = ADCON0.3 // ADC Channel Select bits
#bit CHS0    = ADCON0.2 // ADC Channel Select bits
#bit GODONE  = ADCON0.1 // ADC Conversion Status bit
#bit ADON    = ADCON0.0 // ADC Enable bit

#byte ADRES = 0x08 // ANALOG CONVERSION RESULT REGISTER


Also I tested with your code, it's the same problem Sad
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Wed Nov 25, 2009 4:17 pm     Reply with quote

Will a piece of the .lst file help?

Code:
....................    test1 = 100;
000B:  MOVLW  64
000C:  MOVWF  0C
....................    test2 = 100;
000D:  MOVLW  64
000E:  MOVWF  0D
....................    test3 = 1;
000F:  MOVLW  01
0010:  MOVWF  0E
.................... 
....................    if(test1 > (100-test3))
0011:  MOVF   0E,W
0012:  BSF    04.5
0013:  BSF    04.6
0014:  SUBWF  04,W
0015:  SUBWF  0C,W
0016:  BTFSC  03.2
0017:  GOTO   01C
0018:  BTFSS  03.0
0019:  GOTO   01C
....................    {
....................       GP0 = 1;
001A:  BSF    06.0
....................    }
....................    else
001B:  GOTO   01D
....................    {
....................       GP0 = 0;
001C:  BCF    06.0
....................    }
....................    while(1);
001D:  GOTO   01D


I don't know ASM code, but I don't see any GOTO 01A where the GP0=1 is.
John P



Joined: 17 Sep 2003
Posts: 331

View user's profile Send private message

PostPosted: Thu Nov 26, 2009 12:53 am     Reply with quote

The jump to GP0 = 1 is made in line 0018, BTFSS 03.0. That means "Test bit and skip next instruction if bit is set", and 3.0 is the carry bit, which gets set if a quantity is subtracted from the W register leaving a negative or zero result (I think that's right). So if you skip around a GOTO (that's line 0019) you end up at line 20. But what that earlier stuff is all about, I don't know. My guess is that it's what happens if you do math on signed 8-bit numbers.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Nov 26, 2009 1:50 am     Reply with quote

I checked with MPLAB simulator and found, that the reported faulty behaviour is still present with PCB V4.100, but not e.g. in PCM. It's one of various cases, where a new bug has been introduced in CCS C V4, V3.224 is handling the code correctly.
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Thu Nov 26, 2009 1:52 am     Reply with quote

Oh I see.

Signed? According to my understanding, int8 is default unsigned...
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Thu Nov 26, 2009 1:54 am     Reply with quote

FvM wrote:
I checked with MPLAB simulator and found, that the reported faulty behaviour is still present with PCB V4.100, but not e.g. in PCM. It's one of various cases, where a new bug has been introduced in CCS C V4, V3.224 is handling the code correctly.

Well, I don't think I really need V4 so perhaps I should go back to V3.224 if this has fewer bugs?
Ttelmah
Guest







PostPosted: Thu Nov 26, 2009 4:17 am     Reply with quote

The listing shown looks totally 'screwed'. You have 'test3', transferred to the W register (sensible), then the code sets bits 5, and bits 6, in the FSR. Now the data sheet says:
"FSR <7:5> are unimplemented and read as ‘1’s",

so setting these makes no sense at all.
It then behaves as if it now thinks the FSR register, is the INDF register, and now addresses the required byte. It doesn't...

The complexity is not signed arithmetic, it is just how to address a second register, while holding a value from another. The technique is 'right', but the address being put into the FSR, is wrong, and it is then using the wrong register to access the result...

I'd go back to an older working compiler, and 'scream'. Fortunately, it is nicely demonstrable.....

It is not V4, that has the problem. The code gives totally sensible results in an older V4 compiler, like V4.07x. However it uses an extra scratch RAM location to perform the arithmetic. It appears that CCS are trying to optimise RAM space in these small chips, by performing the maths using the FSR, without another register, but have just got the workings of it 'wrong'....

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Nov 26, 2009 4:19 am     Reply with quote

Quote:
My guess is that it's what happens if you do math on signed 8-bit numbers.

The result is incorrect for any possible combination of signed or unsigned.
Quote:
According to my understanding, int8 is default unsigned...
Yes, according to the manual - and actually.
Quote:
perhaps I should go back to V3.224 if this has fewer bugs?

Not generally. But I also have a few applications that must be frozen with V3. I don't know, if it's due to bugs or incompatible changes. Practically, the difference doesn't matter much.

Obvious bugs should be corrected, of course. But in practice, you perform a workaround. Possibly, you report the bug to CCS. After that, you won't check with every new version, if the bug is continued and the sparse revision history most likely doesn't tell.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group