| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| allenhuffman 
 
 
 Joined: 17 Jun 2019
 Posts: 643
 Location: Des Moines, Iowa, USA
 
 
			      
 
 | 
			
				| rom * in sub-structure can cause function to not be resolved |  
				|  Posted: Wed Feb 05, 2020 11:33 am |   |  
				| 
 |  
				| I already submitted this to CCS, but I wanted to post it here in case anyone else has stumbled on this. 
 PIC24 CCS compiler, multi-unit compile:
 
 We ran into another issue with structures today, where a function reported:
 
 
  	  | Code: |  	  | *** Error 112 "main.c" Line 21(1,1): Function used but not defined:  ... MakeButton 1087  SCR=4431 | 
 
 We narrowed it down to a "rom int8 *ptr;" in a sub-structure that was being returned by the function. Here is a sample.
 
 button.h
 
  	  | Code: |  	  | #ifndef BUTTON_H #define BUTTON_H
 
 #include <main.h>
 #include <stdint.h>
 
 typedef struct
 {
 rom int8 *Icon_Ptr; // Comment this out, and it works.
 int dummy;
 } Basic_Button_Type;
 
 typedef struct
 {
 uint16_t          Button_Number;
 Basic_Button_Type Basic_Button;
 } Screen_Button_Type;
 
 
 // PROTOTYPE
 Screen_Button_Type MakeButton(unsigned int index);
 
 #endif
 
 | 
 
 button.c
 
  	  | Code: |  	  | #include <main.h> 
 #include "button.h"
 
 Screen_Button_Type MakeButton(unsigned int index)
 {
 Screen_Button_Type tempButton;
 
 tempButton.Button_Number   = index;
 
 //tempButton.Basic_Button.Icon_Ptr = 0x1234;
 
 return tempButton;
 }
 
 | 
 
 main.c
 
  	  | Code: |  	  | #include <main.h> 
 #include <stdint.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "button.h"
 
 #define NUM_BUTTONS 100
 
 //Button_Type Buttons[NUM_BUTTONS];
 
 void main()
 {
 Screen_Button_Type Buttons[NUM_BUTTONS];
 
 for (int idx=0; idx<NUM_BUTTONS; idx++)
 {
 Buttons[idx] = MakeButton (idx);
 }
 
 for (int idx=0; idx<NUM_BUTTONS; idx++)
 {
 printf ("Button %u - Number:%u\r\n",
 idx,
 Buttons[idx].Button_Number);
 }
 
 while(TRUE);
 }
 
 | 
 
 When we build this, it reports MakeButton() isn't there. If we comment out the "rom int8 *Icon_Ptr;" line in the buttons.h header file, the function is magically available.
 
 Our real project was actually using a function in other files, just fine, but in main.c or another .c file that function would not resolve.
 
 We just moved the "rom" thing into the top structure and everything is fine, though we hope to have a fix so we can put it back where we wanted it.
 _________________
 Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
 Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
 http://www.whywouldyouwanttodothat.com ?
 
 Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
 |  |  
		|  |  
		| temtronic 
 
 
 Joined: 01 Jul 2010
 Posts: 9589
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Feb 05, 2020 12:34 pm |   |  
				| 
 |  
				| I've never heard of 'perfect programs' when using "multi-unit compile: ". Historically the compiler has been a 'one pass - one program' type environment.
 
 Every once in awhile, we see postings of 'odd' or 'strange' behaviour and someone usually figures it relates to attemping MCU.
 
 I've never given it much thought since PCM v2.540 and PIC16C84s.
 |  |  
		|  |  
		| allenhuffman 
 
 
 Joined: 17 Jun 2019
 Posts: 643
 Location: Des Moines, Iowa, USA
 
 
			      
 
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19967
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Feb 06, 2020 4:17 am |   |  
				| 
 |  
				| I think this again ties into function overloading. 
 ROM pointers are actually a very complex construction. I'm not at all
 surprised that these can't be exported between compilation units. Perhaps
 this should be a documented restriction. Problem is that these rely on
 a table built as part of the compile for resolution. Since this won't be
 passed with import/export, result, problem....
 What's happening is that the structure declaration is being 'simplified'
 to remove this when exported. This results in the function no longer actually
 'matching' it's declaration, so the imported version does not give the
 physical definition for the function. So the message.
 
 I think it really is worth saying that CCS is fundamentally a single pass
 compiler. The support for MCU's, has always been limited, and it is far
 better not to use it. A very large percentage of the problems are when
 people insist on using CCS with MCU's.
 |  |  
		|  |  
		| allenhuffman 
 
 
 Joined: 17 Jun 2019
 Posts: 643
 Location: Des Moines, Iowa, USA
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Thu Feb 06, 2020 8:41 am |   |  
				| 
 |  
				| There's a related issue we found, and I went and created overload functions for a half dozen types (structure, int, char *, float, double, etc.) and ran some tests on that. I found another issue where, since you can't overload a (void) function, as soon as you have one, it won't be resolved if you have a prototype for it. Removing the prototype allowed it to work. 
 As we may migrate to another architecture down the line, I am trying to make all new code modular and portable. Which is often not possible here
  _________________
 Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
 Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
 http://www.whywouldyouwanttodothat.com ?
 
 Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
 |  |  
		|  |  
		| jeremiah 
 
 
 Joined: 20 Jul 2010
 Posts: 1401
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Feb 06, 2020 7:36 pm |   |  
				| 
 |  
				|  	  | allenhuffman wrote: |  	  | As we may migrate to another architecture down the line, I am trying to make all new code modular and portable. Which is often not possible here
  | 
 Modular is doable.  We have tons of modular code here.  Portable is a bit open ended.  CCS C is a K&R version 1 variant, so if you want it portable to an ANSI compiler, then you probably won't get there easily.  They are effectively very different languages.  ANSI C has a lot more semantics defined than K&R, which is very open ended.
 
 CCS C is very portable among different PIC chips, which is the target they are aiming for.  Note that using multiple compilation units is not a requirement for modularity or portability, so I agree with Ttelmah that one should stick to single file compilation for a single pass compiler.  At least until they work out all the kinks in multiple file compilation.
 
 If you want portability, I would recommend using a top down method rather than bottom up.  Doing this I have been easily able to move code I made in CCS to an 8051 microcontroller, a cortex M0+ arm, a cortex M4, and a Jetson TX2 without hardly any changes, just the low level peripheral functionality at the bottom of my design.  In addition, I have been able to simply replace C files in order to completely change drivers to external interfaces (like switch to a SPI interface chip from an I2C chip for example) with no change to my business logic.
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19967
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Feb 07, 2020 3:15 am |   |  
				| 
 |  
				| Totally. 
 I use the same libraries on projects here on Raspberry Pi, Arduino, and
 PIC. However it is vital to actually understand the differences in meanings
 that some things have. ROM * in the first two, does not actually result
 in things stored in ROM. In ANSI C, ROM * is just a signal to say that the
 RAM values cannot be changed. In CCS C it instead means a value actually
 'held' in ROM. Given the different memory architectures, this is a very
 important difference. It is historical. CCS actually started to use 'ROM' as a
 keyword before it was introduced in ANSI C. The equivalent to ROM in
 the Arduino, is PROGMEM.
 Write using original K&R syntax. Don't try to use later constructs. Then
 when using anything like ROM *, only use this when you actually want to
 produce the real effect of storage in ROM, and change this to match the
 processor you are using. 'Portability' requires you to understand the
 different processor architectures and code for them. Code for a Harvard
 architecture is always going to be different to that for Von-Neumann
 architecture and you need to understand the abilities and limitations
 as you write.
 |  |  
		|  |  
		| allenhuffman 
 
 
 Joined: 17 Jun 2019
 Posts: 643
 Location: Des Moines, Iowa, USA
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Fri Feb 07, 2020 10:22 am |   |  
				| 
 |  
				| For anyone interested, CCS has an official document about their ANSI compliance, and notes areas where they aren't. 
 http://www.ccsinfo.com/downloads/ansi_compliance.pdf
 
 The Microware Ultra-C compiler for OS-9 was similar. While it was a fairly-strict ANSI-C compiler, there were some things that could not be done due to OS-9 using  position-independent re-entrant code (I forget what, but I know something about "const" there was handled differently).
 _________________
 Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
 Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
 http://www.whywouldyouwanttodothat.com ?
 
 Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
 |  |  
		|  |  
		| jeremiah 
 
 
 Joined: 20 Jul 2010
 Posts: 1401
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Feb 07, 2020 11:31 am |   |  
				| 
 |  
				| 
 Keep in mind that they update the checklist.  It isn't fully vetted by the ISO standards committee.  It's often times wrong as well.  I've sent multiple reports about non compliance.  They fixed some but still haven't fixed all (though they are working on it).
 
 The ANSI C standard defines a lot of "abstract machine" semantics that aren't on that checklist and that they don't support.
 
 For example, Duff's Device was vetted by the ANSI committee as standard based on the semantics as defined in the ANSI standard.  However, CCS supports K&R semantics (which are largely open and not defined), so it cannot compile the ANSI version of Duff's Device:
 
 
  	  | Code: |  	  | void main()
 {
 short *to, *from;
 int count;
 int n = (count + 7) / 8;
 
 switch (count % 8) {
 case 0: do { *to = *from++;
 case 7:      *to = *from++;
 case 6:      *to = *from++;
 case 5:      *to = *from++;
 case 4:      *to = *from++;
 case 3:      *to = *from++;
 case 2:      *to = *from++;
 case 1:      *to = *from++;
 } while (--n > 0);
 }
 }
 
 | 
 
 which happily compiles in GCC but CCS doesn't understand because it doesn't implement ANSI control structure semantics as defined in the standard.
 
 NOTE:  if you are wondering the use of the example, it's useful in various types of optimizations on specific processors and is the foundation to protothreads (I implemented them in CCS C, but had to use a different method with compiler extensions).
 
 NOTE:  Sorry if this sounds like I am disagreeing with you.  Not my intention.  My hope is that you just keep it in mind when you are designing for portability.  And I hope you keep submitting the bugs you find to CCS via their support email.  The more that can get fixed, the better.
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19967
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Feb 07, 2020 1:41 pm |   |  
				| 
 |  
				| I actually asked if they could change their syntax support to allow this to work some time ago. Perhaps I need to remind them of this!...
  |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |