Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 05:07 30 Apr 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : C-lib limitation reducement

Author Message
Nathan
Regular Member

Joined: 10/01/2016
Location: Germany
Posts: 49
Posted: 01:56pm 10 Jan 2016
Copy link to clipboard 
Print this post

Hi,

it's time to give soemting back to the community.
Sor what about a little bit of

static const ..
switch ..

support for c-libs?

I have attached some C-example code to show how it works.

// How to use ...
// please use the following settings for the cproject:
//
// xc32-gcc properties
// have symbols : x
// exclude float lib: x
// add options : -fPIC -mno-abicalls -shared -membedded-data -mno-long-calls -fno-jump-tables -mno-jals -mgpopt -Wuninitialized -Wunused-variable -Wunused-value -Wunreachable-code
// optimization : 1
//
// x32-ld properties
// libraries
// exclude standard libs: x
// do not link startup code: x
// exclude floating point lib: x
//
// the static const var data will be stored within the .rodata section in elf file
// this data has to be add to the end of the cfunctions data. Address gaps has to be closed by nop
// entries.
// Cfuncgen and cfgen has to be modified to output .rodata following a)-c).
// a) section order
// .text: output
// .rodata: output unmodified
// .dinit (contense of .dinit can be ignored)
// b) section order
// .dinit (contense of .dinit can be ignored)
// .text: output
// .rodata: output unmodified
// c) section order <------- take care critical
// .text: output
// .dinit output unmodified
// .rodata output unmodified
// for the moment you hav to add manually the output
//
// switch seems to work up to 6 entries + default, not clear what happens behind the limit
//


/*
* File: demoConst.c
* Author: Nathan
*
* Created on 13. Dezember 2015, 20:25
*/
#define _SUPPRESS_PLIB_WARNING
#define _DISABLE_OPENADC10_CONFIGPORT_WARNING

#include <xc.h> // Required for SFR defs
#include <sys/attribs.h> // Required to use __longramfunc__
// and __ramfunc__ macros.
#include "CFunctions.h"

//
// make some address calculations to get the flash position of the actual
// function. This should be possilbe by fp pointer, too.
// I do not trust the fp, lets use the ra register instead
// (a) is point to function, (b) pointer to label, (c) pointer for result
// if a is set to NULL the offset will be output, usefull fo static const calculation.
//

__attribute__((noinline)) void getFPC(void *a, void *b, volatile unsigned int *c)
{
*c = (unsigned int) (__builtin_return_address (0) - (b -a)) ;
}


void main(long long *_iii, long long *_ii, long long *_ax) {

//keep the following lines together, lableAdr will contains adress of main
//if used within an other function, please adapt main -> function name
volatile unsigned int libAddr ;
getFPC(&main,&&getFPCLab,&libAddr) ; // warning can be ignored, stupid editor
getFPCLab: { }
//

unsigned int offs = libAddr - (unsigned int)&main ;
// hi basic this is my flash address (loadable graphic functions=
_ax[0] = libAddr ;
//static const unsigned char asd[] __attribute__((section (".constdata,r"))) = "Dies ist ein Test." ;
// --> static const is required
static const unsigned char asd1[] = "Hi, " ;
static const unsigned char asd2[] = "if you can" ;
static const unsigned char asd3[] = "read this" ;
static const unsigned char asd4[] = "then you" ;
static const unsigned char asd5[] = "got it running." ;
static const unsigned char asd6[] = "---------------" ;
static const unsigned char asd7[] = "7" ;
static const unsigned char asd8[] = "8" ;
static const unsigned char asd9[] = "9 " ;
static const unsigned char asd10[] = "(default)" ;

unsigned char *_string = (unsigned char *)_ii;
unsigned int i = 0 ;
unsigned int iii = *_iii ;
unsigned char * xptr ;
//
// simple switch example (this is a stupid examplr)
//
switch ( iii ) {
case 1:
xptr = (unsigned char *)asd1 ;
break ;
case 2:
xptr = (unsigned char *)asd2 ;
break ;
case 3:
xptr = (unsigned char *)asd3 ;
break ;
case 4:
xptr = (unsigned char *)asd4 ;
break ;
case 5:
xptr = (unsigned char *)asd5 ;
break ;
case 6:
xptr = (unsigned char *)asd6 ;
break ;
case 7:
xptr = (unsigned char *)asd7 ;
break ;
case 8:
xptr = (unsigned char *)asd8 ;
break ;
case 9:
xptr = (unsigned char *)asd9 ;
break ;
default:
xptr = (unsigned char *)asd10 ;
}
//
// the next is required for every access of a const declaration
// add the offset ( to adapt the different locations between cfunction in flash#
// and locations during compilation/linking), manual gop
// --> you need an address, which you can manipultate <--
//
xptr += offs ;

//
// lets access the const data string, and copy it to the basic-ram
//
for(i=1; *xptr ;i++){
_string= (unsigned char)*xptr;
xptr++ ;
}
_string[0]= i-1 ;
}


Have fun,

Nathan.
 
Nathan
Regular Member

Joined: 10/01/2016
Location: Germany
Posts: 49
Posted: 02:05pm 10 Jan 2016
Copy link to clipboard 
Print this post

Hi,

I think it should be fair to show the basic test script, too.

Happy testing,

Nathan

PS. I really hope that the approach works not only for my test data
So lets see what you can do with the new possibilities.


'
' switch and const demo by Nathan Jan. 2016
'
Dim cadd%, b$, Y%, i%

Do
cadd% = Peek(cfunaddr constTest)
Print "Hi Csub this is your address: " + Hex$(cadd%)
Print ""

For i% = 1 To 10
constTest(i%,b$,Y%)
Print b$
Next i%

Print ""
Print "Hi, I know that Im at: " + Hex$(Y%)
PRINT ""
Pause 1000
Loop


CSub constTest

00000008
27bdfff8 afbf0004 00852023 03e42021 acc40000 8fbf0004 03e00008 27bd0008
27bdffd0 afbf002c afb30028 afb20024 afb10020 afb0001c 00809821 00a08021
00c08821 3c129d00 26440020 3c059d00 24a50060 27a60010 0411FFE9 00000000
8fa20010 26520020 00529023 8fa20010 ae220000 ae200004 8e620000 24030005
10430025 2c430006 10600011 24030007 24030002 1043002f 2c430003 10600006
24030003 24030001 54430028 3c029d00 10000012 3c029d00 10430012 24030004
54430022 3c029d00 10000011 3c029d00 10430016 2c430007 54600012 3c029d00
24030008 10430014 24030009 54430017 3c029d00 10000013 3c029d00 10000017
24420218 3c029d00 10000014 24420200 10000012 244201f4 3c029d00 1000000f
244201e4 1000000d 244201d4 3c029d00 1000000a 244201d0 3c029d00 10000007
244201cc 10000005 244201c8 10000003 244201bc 3c029d00 2442020c 00529021
92430000 1060000c 24020001 24050100 02022021 a0830000 26520001 92430000
10600005 24420001 1445fffa 02022021 10000002 2442ffff 2442ffff a2020000
8fbf002c 8fb30028 8fb20024 8fb10020 8fb0001c 03e00008 27bd0030

66656428
746c7561
00000029
00002039
00000038
00000037
2d2d2d2d
2d2d2d2d
2d2d2d2d
002d2d2d
20746f67
72207469
696e6e75
002e676e
6e656874
756f7920
00000000
64616572
69687420
00000073
79206669
6320756f
00006e61
202c6948
00000000

End CSub
 
Nathan
Regular Member

Joined: 10/01/2016
Location: Germany
Posts: 49
Posted: 02:16pm 10 Jan 2016
Copy link to clipboard 
Print this post

Hi,

seems the forum software does not like c-code and modifies it.
Therefore I attached the original file. The example on my first mail
will not work. Please use the attached file instead.

Nathan

2016-01-11_001405_demoConst.zip
 
BobD

Guru

Joined: 07/12/2011
Location: Australia
Posts: 935
Posted: 07:24pm 10 Jan 2016
Copy link to clipboard 
Print this post

Nathan

can you explain a bit more about what you are presenting. Many of us here have not much knowledge of C. Even though what you're presenting may be quite obvious it misses me completely.

thanks
Bob

edit: as you noticed, this forum uses square brackets (name?) for formatting so when they occur in code then they may mess up the output.
Edited by BobD 2016-01-12
 
Nathan
Regular Member

Joined: 10/01/2016
Location: Germany
Posts: 49
Posted: 08:43pm 10 Jan 2016
Copy link to clipboard 
Print this post

Hi Bob,

take a string:
a$ = "test"

it is located within the basic ram.

If you want to have the same within the C-lib the
situation is a little bit different:

static const unsigned char A\[\] = "test" ;

the compiler/linker puts them in a special section .rodata in flash memory
(at an fixed address). This is fine as long as you compile a complete design.
For the clib function you need the data together with the function itself.
So the situation changed, the data is not anymore at the expected place.
The idea for fixing is to add the offset between the expected .rodata and
the csub address.

This is easy if you can find out the difference between the actual data address
and the address during compilation/linking.

It is done by the following lines:
volatile unsigned int libAddr ;
getFPC(&main,&&getFPCLab,&libAddr) ; // warning can be ignored, stupid editor
getFPCLab: { }

&& is used to get the address of the label getFPCLab.
*libAddr contains the real address of the clib in flash (after getFPC finished).

In case you replace &main with NULL *libAddr contains directly the offset.
In the example above the offset would be

unsigned int offs = libAddr - (unsigned int)&main ;

so you will get the "t" for

A[0+offs]

Example (pseudo code):
A is at 0x9d00000 during compilation/linking
A is at 0x9d00600 after loading the c-lib with basic

so for access the 0x0600 is the offset, which has to be taken for access.

Looks a little bit strange, but works. Just play with the example "c" and basic prog.
Please take care: at the moment the .rodata has to be taken out of the disassembly file. cfgen can not extract them, yet.

regarding the switch construct it is a special syntax for replacement of nested if / else. The compiler optimized it in the past so that it could not be used within csub(cfunctions). During my tests it works now.

The funny thing is that the csub/function can find out by itself, where it is locaded. So initialization routines for tft modules can use it. Also the
initialization data can be placed within a const var, which allows smaller
functions.

I hope this explanation helps a little bit to understand the idea behind the c-code.
It is not my dream implementation, but it seems to work.

Nathan













 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3659
Posted: 10:59pm 10 Jan 2016
Copy link to clipboard 
Print this post

Hopefully a way to extend CFunctions (which now have position-independent code) to get position-independent data and C's "switch" (which in effect wants p-i data).

(Give PeterM a chance to try it...)

The idea is to persuade the toolchain (compiler, linker, etc) to store the data in the way needed. gcc's linker uses "sections" which you can relocate, change addresses, etc - but it can mess with your head getting it right.

John
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8585
Posted: 11:05pm 10 Jan 2016
Copy link to clipboard 
Print this post

Hi Nathan

This is very interesting stuff.

On posting C code, if you avoid using "i" as a loop index it is normally OK. <open-square-bracket>i<close-square-bracket> causes the problem.

What version of the compiler are you using?

I'm still suspicious of "switch". I suspect the problem arises when there is more significant code in the various clauses at which point the compiler does some optimisation.

Please could you post a zip of the complete MPLABX project.

I wrote the original version of cfgen and Tassyjim then converted it to the compiled Basic version we are using. Unfortunately, I have one of those brains that completely forgets something when it is finished so it may take some time to work out how to read .rodata and incorporate it in the CFunction output but being able to use static constants would be a huge advantage so I'll certainly look at it.

Great work

Peter

 
Nathan
Regular Member

Joined: 10/01/2016
Location: Germany
Posts: 49
Posted: 11:03am 15 Jan 2016
Copy link to clipboard 
Print this post

Hi Peter,

sorry for delay, I can only answer on the weekends. During the week I have no access to private emails/this forum.

Regarding the versions:
MPLAB X IDE v3.05
xc32 v1.34

Please try the following steps (It is my readme file. I use, too)

Please take care in my posts of the beginning of the week is a mistake:
(not use the -shared option for gcc)

Every comment/reply is welcome.

That's my workflow:
1.) new project
... enbeded --> stand alone project
2.) Family 32bit ... pic32
PIC32MX170F256D
3.) select simulator
4.) select compiler xc32
5.) project name < as you want >
project location < as you want >

--> go into the project directoy and copy the c source file into it
--> copy the clib library header file into it, to

open project (tab on the left side of the window, not the file menu!!)
--> the one you just created, plus symbol.
right mouse button on the "header" (use add existing item, add the .h file)
do the same for the "source files" entry (use add existing item, add the .c file)

go onto the properties of the project:
make the following settings:

//
// xc32-gcc properties
// have symbols : x
// exclude float lib: x
// add options : -fPIC -mno-abicalls -membedded-data -mno-long-calls -fno-jump-tables -mno-jals -mgpopt -Wuninitialized -Wunused-variable -Wunused-value -Wunreachable-code
// optimization : 1
//
// x32-ld properties
// libraries
// exclude standard libs: x
// do not link startup code: x
// exclude floating point lib: x
--> it is important to not forget the linker options, because in other case the gap between the text data and the .rodata is full of lib functions.

// Note after modifying the above settings, leave MPLAB X and restart it!!!!!

--> somehow the things only work after restart, really leave MPLAB X

compile the project.
run cfuncgen, take a look into the .dis file. (--> merge !!!!!!)
copy the output in the .dinit/.rodata (only the data long long) at the
end of the cfunction

//
// the static const var data will be stored within the .rodata section in elf file
// this data has to be add to the end of the cfunctions data. Address gaps has to be closed by nop
// entries.
// Cfuncgen and cfgen has to be modified to output .rodata following a)-c).
// a) section order
// .text: output
// .rodata: output unmodified
// .dinit (content of .dinit can be ignored)
// b) section order
// .dinit (content of .dinit can be ignored)
// .text: output
// .rodata: output unmodified
// c) section order <------- take care critical
// .text: output
// .dinit output unmodified
// .rodata output unmodified
//
// for the moment you have to add manually the output of .dinit .rodata
//
// check .dinit section in .dis file
// 00000000
// 22222222
// 22222222
// 22222222
// the above is O.K. a difference shows that auto variables are used (error)
//
//


 
Nathan
Regular Member

Joined: 10/01/2016
Location: Germany
Posts: 49
Posted: 11:13am 15 Jan 2016
Copy link to clipboard 
Print this post

Hi John,

for the switch usage, I hope the following addtional setting is enough to get it
working. Please try the following entry in addition to the -PIC option.
-fno-jump-tables

Please set and leave MPLAB. --> Restart MPLAB. --> compile

Nathan


 
Nathan
Regular Member

Joined: 10/01/2016
Location: Germany
Posts: 49
Posted: 11:54am 15 Jan 2016
Copy link to clipboard 
Print this post

Hi Peter,
Hi John,

I attached a simplified test case, which works without switch statement.
It uses address tables for the access. Maybe it is easier to understand.
and also for the enhancement of the cfgen prog.

My boss also said I should not use i, ii, iii, iiii
as counter or help variables.



Nathan

2016-01-15_214925_demoConst22.zip 2016-01-15_214942_test22.zip
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024