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 support@ccsinfo.com

Debugger fix???
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

Debugger fix???
PostPosted: Wed Feb 24, 2016 10:44 am     Reply with quote

Please excuse me if I sound frustrated. It is because I am. Why the heck can't CCS fix their debugger. Every new version has new problems. Sometimes an old problem is fixed but I think it is generally going downhill!
Here is a small example from the version 5.053 debugger:

I set a breakpoint in a function that has a passed parameter of type *int:
Code:
void WriteTable (char *buf, int *pTableNo)

Then I try to find out the value that pTableNo is pointing to. First I hover the mouse over the pointer name and I get a value of 0x00139. No way is that correct but I look at the passed value and it is:
Code:
&Td.TableCount
Tablecount is an int and is set to 2. So then I try to use the eval window in the debugger. Here are the reults:
Code:
*pTableNo
65282
pTableNo [0]
313


Three different ways of looking at a value and three wrong answers. Not only that, but the eval window gives answers that are not even possible for an integer! How the he!! is a guy supposed to do good work if the tools do not work right?

I don't have time to do a formal complaint to CCS and besides I have done that for other previous versions with no results or even discussion. Hopefully someone from CCS sees this complaint but it does not matter much because by the time anything is done about it I will be suffering with a different bug in the debugger.

Regards, Russ
Ttelmah



Joined: 11 Mar 2010
Posts: 19396

View user's profile Send private message

PostPosted: Wed Feb 24, 2016 11:40 am     Reply with quote

0x139, will be correct....

It is the address that the pointer is pointing 'to'.

The default size for the eval, is the same as for statements in the compiler evaluation, so int16. *pTableNo is returning the 16bit integer at this address 65282, is 0xFF02. Guess what the '02' is what you want. Tell eval to return an int8 (cast), and it'll give the correct value.
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

PostPosted: Thu Feb 25, 2016 2:03 pm     Reply with quote

> Tell eval to return an int8 (cast), and it'll give the correct value.

Ok, but I should not have to do that. The compiler knows (and the debugger should know) that the integer is an int8. So when I tell it *pointer, or especially pointer[0], it should return the correct value. I have never seen another debugger that could not do this. And in any case it does not make any sense to return the pointer address!

And, when I hover the mouse over the pointer name, at least one of two things should happen, if not both. One is that the pop up info should show both the pointer address and the value it is pointing to (just as when hovering over a char*). Or, at least if I highlight the pointer name plus the * in front of it then it should show me the value.

The same thing applies if I were to highlight a structure name, like 'Td.TableNumber", it should show me what is in TableNumber. but it doesn't.

I get the feeling that the debugger people never looked at a good debugger or do not care to put in the effort.

It turned out that my code problem was not related to the value at the pointer, that was working correctly even if it is hard to get the debugger to show it. It was actually a compiler problem:
Code:
addr = ATTN_TABLES + (long) TABLE_SIZE * count;
where count and addr are long (int16), and the upper case labels are defines.

This would not work until I cast TABLE_SIZE to long. It would calculate the correct address when count was zero or 1, but gave the wrong result when count was 2. However in another function the same code works without the cast???? Totally strange.

Oh well - onward and upward!

Regards, Russ
Ttelmah



Joined: 11 Mar 2010
Posts: 19396

View user's profile Send private message

PostPosted: Thu Feb 25, 2016 3:35 pm     Reply with quote

MPLAB, also does not correctly identify sizes. It'll do it for some things but not others. A pointer is implicitly capable of pointing to anything, and indeed it is one of the powers of C that you can use the same pointer to address different objects.

Your expression would depend on the type of count. One trick would be in the macro definition where you #define TABLE_SIZE define it as a long. So:

#DEFINE TABLE_SIZE 150L //whatever it's size is.

If count is an integer, and Table size is 128 or larger, then you must cast one or the other value to an int16 for the maths to work.
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

PostPosted: Fri Feb 26, 2016 7:22 am     Reply with quote

Ok Ttelmah, but count is a long and TABLE_SIZE is 124. Also ATTN_TABLES is 32.
In every other compiler, if you multiply or divide a lower type by a higher type, the compiler will do the calculation at the higher type and then downcast it if necessary if assigning the result to a lower type. This works with sizes of integers and when mixing integers with floats or doubles. It even works in a typesafe language like C++, except that you would get a warning if the result had to be downcast. (in this case the result is not downcast though.)

Regards, Russ
Ttelmah



Joined: 11 Mar 2010
Posts: 19396

View user's profile Send private message

PostPosted: Fri Feb 26, 2016 8:47 am     Reply with quote

Don't use the words 'long', or 'short', they mean too many different things. For instance a 'short' in many cases is an int8, while on some compilers it is an int16, and in CCS an int1...

It is much safer to either use int8, int16 etc., or better to load the standard type library and use this.

Now 'what processor are you on'?.

If (for instance), this is PCD (PIC24 etc.), then 'long' actually implies int32. The default sizes for everything would be int16, so the cast would then make a difference, casting 'up' to int32.

If count is int16, and this is PCM/PCH, then casting to long should not make any difference, unless the definition of 'long' has been changed somewhere, or count is not actually the variable you think it is (another 'count' declared somewhere). The compiler _will_ use int16, if the copy of 'count' being used here is int16.
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

PostPosted: Sat Feb 27, 2016 7:13 am     Reply with quote

Hi Ttelmah. Well you would think so. Currently I am working mostly with two processors, PIC18F4682 and PIC18F6723. Here are the two functions in question in full:
Code:
#define ATTN_TABLE_SIZE   0x7C   // size of each attn table
#define ATTN_ITEM_SIZE   4      // size of each attn item (attn, temp, volts)
#define ATTN_TABLES      0x20   // Start of Attenuation tables in internal EEPROM
enum AttnBufPositions { AP_LAST, AP_COUNT, AP_START };

void WriteAttnTable (char *buf, int *pTableNo)
{
   int      i, bytes;
   long   count, addr;

   bytes = buf [AP_COUNT];
   char   *p = &buf [AP_START];

   count = *pTableNo;
   addr = ATTN_TABLES + (long) ATTN_TABLE_SIZE * count;
   for (i=0; i < bytes; ++i)
      write_eeprom (addr++, p [i]);
   ++(*pTableNo);

   if (buf [AP_LAST] == 1) {
      write_eeprom (EE_ATCOUNT, count);
      SetTableLoaded (TT_ATTN, true);
      OpData.bRecalc = true;   // force recalculation of all control voltages
      gMode = MO_OPERATE;
   }
}

and
Code:
void SendAttnTable (char *buf, int TableNo)
{
   int      i, len;
   long   tCount, iCount;
   long   addr, temp;

   if (! IsTableLoaded (TT_ATTN)) {
      strcpy (buf, "0,0");
      SendSerial (CM_TABLES, buf, 3);      // count = 0
      return;
   }
   
   tCount = FindIntToken (buf, 1);

   if (tCount == 0) {   // initial request
      len = sprintf (buf, "%u", TableNo);
      SendSerial (CM_TABLES, buf, len);
      return;
   }

   --tCount;   // make table count zero based
   addr = ATTN_TABLES + tCount * ATTN_TABLE_SIZE;
   temp = ReadEEpromLong (addr);
   iCount = ReadEEpromLong (addr+2);

   if (iCount < 255) {   // protect against invalid eeprom value
      // Send all the table items along with a last flag
      buf [0] = temp;
      buf [1] = icount;

      addr += 4;
      for (i=0; i < iCount * ATTN_ITEM_SIZE; ++i)
         buf [i+2] = read_eeprom (addr++);

      SendSerial (CM_TABLES, buf, iCount * ATTN_ITEM_SIZE + 2);
   }
}

The first function is the one I was trying to debug and I ended up creating a new variable 'count' so I could see the value easily. Prior to that I was using *pTableNo, so the multiplication looked like:
Code:
   addr = ATTN_TABLES + ATTN_TABLE_SIZE * *pTableNo;

That did not work either. After I determined it was not the value of *pTableNumber and had substituted 'count' there I still found I had to cast the value ATTN_TABLE_SIZE to a long. However the second function uses the same code and works ok without the case...

Russ
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

PostPosted: Sat Feb 27, 2016 7:27 am     Reply with quote

Hi Ttelmah. Well you would think so. Currently I am working mostly with two processors, PIC18F4682 and PIC18F6723. Here are the two functions in question in full:
Code:
#define ATTN_TABLE_SIZE   0x7C   // size of each attn table
#define ATTN_ITEM_SIZE   4      // size of each attn item (attn, temp, volts)
#define ATTN_TABLES      0x20   // Start of Attenuation tables in internal EEPROM
enum AttnBufPositions { AP_LAST, AP_COUNT, AP_START };

void WriteAttnTable (char *buf, int *pTableNo)
{
   int      i, bytes;
   long   count, addr;

   bytes = buf [AP_COUNT];
   char   *p = &buf [AP_START];

   count = *pTableNo;
   addr = ATTN_TABLES + (long) ATTN_TABLE_SIZE * count;
   for (i=0; i < bytes; ++i)
      write_eeprom (addr++, p [i]);
   ++(*pTableNo);

   if (buf [AP_LAST] == 1) {
      write_eeprom (EE_ATCOUNT, count);
      SetTableLoaded (TT_ATTN, true);
      OpData.bRecalc = true;   // force recalculation of all control voltages
      gMode = MO_OPERATE;
   }
}

and
Code:
void SendAttnTable (char *buf, int TableNo)
{
   int      i, len;
   long   tCount, iCount;
   long   addr, temp;

   if (! IsTableLoaded (TT_ATTN)) {
      strcpy (buf, "0,0");
      SendSerial (CM_TABLES, buf, 3);      // count = 0
      return;
   }
   
   tCount = FindIntToken (buf, TCOUNT_LOC);  // TCOUNT_LOC is 1

   if (tCount == 0) {   // initial request
      len = sprintf (buf, "%u", TableNo);
      SendSerial (CM_TABLES, buf, len);
      return;
   }

   --tCount;   // make table count zero based
   addr = ATTN_TABLES + tCount * ATTN_TABLE_SIZE;
   temp = ReadEEpromLong (addr);
   iCount = ReadEEpromLong (addr+2);

   if (iCount < 255) {   // protect against invalid eeprom value
      // Put the temperature and item count plus all the table items in the send buffer
      buf [0] = temp;
      buf [1] = icount;

      addr += 4;
      for (i=0; i < iCount * ATTN_ITEM_SIZE; ++i)
         buf [i+2] = read_eeprom (addr++);

      SendSerial (CM_TABLES, buf, iCount * ATTN_ITEM_SIZE + 2);
   }
}

The first function is the one I was trying to debug and I ended up creating a new variable 'count' so I could see the value easily. Prior to that I was using *pTableNo, so the multiplication looked like:
Code:
   addr = ATTN_TABLES + ATTN_TABLE_SIZE * *pTableNo;

That did not work either. After I determined it was not the value of *pTableNo and had substituted 'count' there I still found I had to cast the value ATTN_TABLE_SIZE to a long. However the second function uses the same code and works without the cast...

Russ
Ttelmah



Joined: 11 Mar 2010
Posts: 19396

View user's profile Send private message

PostPosted: Sat Feb 27, 2016 12:26 pm     Reply with quote

The obvious thing is that the value in both cases is an int, not an int16 (long). So 'of course' a cast will be needed. In the second case, you are moving the int value into an int16, so then 'of course' the cast is not needed. Moving an int into an int16, performs an automatic cast.....
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

PostPosted: Sat Feb 27, 2016 7:48 pm     Reply with quote

No, the only difference is in the order of the multiplication:
Code:
   addr = ATTN_TABLES + tCount * ATTN_TABLE_SIZE;
vs   addr = ATTN_TABLES + (long) ATTN_TABLE_SIZE * count;

In both case the result is moved into an int16. But in the case that works the count value is placed before the define. The order should not matter, but apparently it does.

Thanks, Russ
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Sat Feb 27, 2016 10:25 pm     Reply with quote

Back with v3.236 or v3.249 I discovered the hard way that the order was important in a calculation. Can't remember which way round was bad, but there was a mistake in the way the compiler was handling things. PCM was actually the one to find the issue.
temtronic



Joined: 01 Jul 2010
Posts: 9186
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Feb 28, 2016 7:14 am     Reply with quote

Any calculation that is complicated( to me that's 3 or more things), I 'over use' brackets and casting just to be SURE the compiler does it my way.
It's to easy to 'think' one way, code another and then have the compiler do it a 3rd way.

Sometimes it's better to break down the complicated stuff into several lines, get it working then go back and reduce to a one liner.


Jay
hatchedeck80



Joined: 04 Mar 2016
Posts: 1

View user's profile Send private message

PostPosted: Sun Mar 06, 2016 1:27 am     Reply with quote

temtronic wrote:
Any calculation that is complicated( to me that's 3 or more things), I 'over use' brackets and casting just to be SURE the compiler does it my way.
It's to easy to 'think' one way, code another and then have the compiler do it a 3rd way. That is the way it has always been for an attorney and I am not sure how it will change over time, whether it is a wrongful termination or illegal discrimination. There is another feature request which they were talking about before, but I am not sure if they have implemented it already.

Sometimes it's better to break down the complicated stuff into several lines, get it working then go back and reduce to a one liner.


Jay


I agree, reducing them to one liners is a good idea but a little time consuming, isn't the purpose of debugging to calculate all these complex stuff more efficiently? Still, your point stands as it is. But a better debugger is still needed.


Last edited by hatchedeck80 on Mon Apr 02, 2018 6:49 pm; edited 1 time in total
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

PostPosted: Sun Mar 06, 2016 6:47 am     Reply with quote

Thank you Temtronic. That is exactly my point here - my frustration with the debugger. Here is another one. Suppose you have a for loop formatted like this:
Code:
    for (i=0; i < 10; ++i)
        do something;
    not in loop statement;
When stepping through it with the debugger it will show the next statement as the one after the loop - looking like it has exited the loop. But then another single step and it will return to the for statement. No other debugger I have used does that. If you format the do something statement with braces around it then it will step properly. Why can't the debugger people figure that one out? It has been the same in every version... And why oh why isn't there a control to exit the current function instead of having to put the cursor at the end of the function and then use 'run to cursor'. And why, when you set a breakpoint at a function call, does it actually break at the first line of the function after it is called. It should break just before the function is called so I can decide whether to step into the call or not. Simple stuff but makes a programmers job much easier.

It would be very helpful if someone started paying more attention to the debugger.

Regards, Russ
temtronic



Joined: 01 Jul 2010
Posts: 9186
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Mar 06, 2016 7:22 am     Reply with quote

Yup Russ
Life is complicated ! I've never had a debugger or simulator do it 'my way'. it could be as simple as 'perspective' in how to code. Think of it this way. When you put your shoes and socks on do you put both socks on first then both shoes OR left sock, left shoe, right sock, right shoe? Depends on how you were taught, both eventually come to the same ending.
I do all my debugging running the code in the PIC in the Real World,just the way I've done it for 4 decades and I'm too old to learn 'new fangled ways'!
As for the 'quirks' of the debugger, I'm thinking 'they' have a lot more pressing issues(new PICs, features, etc.) and haven't the time or manpower to 'tweak' minor issues. Perhaps inform 'them'..maybe it's an 'easy' patch?

Jay
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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