![]() |
Forum Index : Microcontroller and PC projects : CMM2: V5.05.04b3a: CSUBs - not for the faint hearted!!!!
![]() ![]() ![]() ![]() |
|||||
Author | Message | ||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
Thank you, I should have RTFM, it didn't have CSUBs in it when I last read it ![]() Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
twofingers Guru ![]() Joined: 02/06/2014 Location: GermanyPosts: 1526 |
Hi Tom, that was a google find (site: thebackshed RoutineChecks). I wouldn't have expected it in the manual either. ![]() It might be interesting to see how Peter uses it in the source code. I needed it for my sorting functions. Best regards Michael causality ≠ correlation ≠ coincidence |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10067 |
All over the place ![]() basically any command that could take a long time will have calls to routinechecks() embedded in any loop structures. The function itself is enabled by a variable set every 2mSec in the main timer interrupt so the overhead of calling it is minimal as it returns immediately if the 2 mSec hasn't elapsed |
||||
twofingers Guru ![]() Joined: 02/06/2014 Location: GermanyPosts: 1526 |
Thanks, Peter, for the explanation! ![]() Michael causality ≠ correlation ≠ coincidence |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
Dear Peter, Is the use of function pointers within CSUBs not supported? #include "ARMCFunctions.h" MMFLOAT doubleit(MMFLOAT *c){ return *c *2.0; } __attribute__((noinline)) void getFPC(void *a, void *b, volatile unsigned int *c) { *c = (unsigned int) (__builtin_return_address (0) - (b -a) - 1) ; } void p_string(const char *s){ volatile unsigned int libAddr ; getFPC(0,&&getFPCLab,&libAddr) ; getFPCLab: { } unsigned char * testData = (unsigned char *)((void *)s + libAddr); MMPrintString(testData); } void p_int(int a,int base){ char b[64]; IntToStr(b,a,base); MMPrintString(b); } void p_float(float a,int m, int n, char c){ // m is the nbr of chars before the decimal point // n is the nbr chars after the point // ch is the leading pad char char b[14]; FloatToStr(b,a, m, n ,c); MMPrintString(b); } void foo(void) { // char s[] = "_Hello World\r\n"; // s[0] = 13; // MMPrintString(s); } typedef void (*function_t)(void); void main(long long int *c, MMFLOAT *b){ volatile unsigned int libAddr ; getFPC(0,&&getFPCLab,&libAddr) ; getFPCLab: { } static const char crlf[]="\r\n"; static const char s1[]="First variable = "; static const char s2[]="Second variable = "; p_string(s1); p_int(*c,10); p_string(crlf); p_string(s2); p_float(doubleit(b),4,2,' '); p_string(crlf); foo(); // *** Hangs if this is uncommented. *** function_t fptr = &foo; fptr(); } I'm using the "merge" option. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10067 |
Never tried but I would assume that could be an issue of absolute addressing in a relocatable module. You may have to play with the same sort of construct as for strings but I'm afraid you are on your own on this one. There is also the strange issue with ARM that the address of a function has one added to it in order to tell it to use THUMB2. I think the first thing will be to look at the generated assembler and see what the compiler is producing. No easy answers on this one I'm afraid |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
Thanks for taking the time to reply Peter. I probably shouldn't speculate but would expect the linker to know that function pointers can't use absolute addressing when compiling position independent code. I did try naively using the same construct as for strings but it didn't work, more research required. I wasn't aware, but again I would have thought the compiler/linker should be handling that detail. Fair enough, I'll add it to the list right after learning THUMB assembler ![]() Actually I can probably finesse the problem and replace my use of function pointers with a really big switch statement, that should be good enough to complete my proof of concept. Thanks again, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10067 |
Out of interest you could try void (*fptr)= foo; fptr(); |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
Sorry Peter, I'm not clear on what you are trying to achieve, this results in: test.c: In function 'main': test.c:55:3: error: called object 'fptr' is not a function or function pointer 55 | fptr(); | ^~~~ test.c:54:10: note: declared here 54 | void (*fptr) = foo; Best regards, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10067 |
Dunno That's how all the function pointers are set up in MMBasic void (*DrawPixel)(int x1, int y1, int c); DrawPixel=DrawPixel16; DrawPixel(x, y, c); Perhaps needs to be two steps as above |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
OK, you were trying to do this: void (*fptr)(void); // equivalent to void (*fptr)(); fptr = foo; // equivalent to fptr = &foo; fptr(); I believe it is the same, but I will give it a go. Thanks, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
As expected same result, and probably the same generated assembler. // Declare fptr to be a pointer to a function with 0 args and no return value. void (*fptr)(void); // Assign the address of a function to 'fptr'. // fptr = foo; // fptr = &foo; // and possibly even // fptr = *foo; // fptr = ***** foo; // are all treated the same, see https://stackoverflow.com/questions/16917043/do-function-pointers-need-an-ampersand fptr = foo; // Call foo via the pointer: fptr(); Apologies if I'm telling you something you already know, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10067 |
Tom A next step could be to print the address of fptr after setting it without calling it. That way you will know where it is pointing and see what is happening i.e . if it is within the CSUB address space |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
Good idea ... however it appears the problem isn't calling the function pointer, it's assigning it to fptr - WTF! #include "ARMCFunctions.h" void p_int(int a,int base){ char b[64]; IntToStr(b,a,base); MMPrintString(b); } void foo(void) { putConsole('*'); putConsole('\r'); putConsole('\n'); } void main(long long int *c, MMFLOAT *b){ putConsole('a'); putConsole('\r'); putConsole('\n'); foo(); putConsole('b'); putConsole('\r'); putConsole('\n'); void (*fptr)(void); putConsole('c'); putConsole('\r'); putConsole('\n'); fptr = &foo; // <--- hangs here, how is that even possible? putConsole('d'); putConsole('\r'); putConsole('\n'); } Any bright ideas, other than look at the assembler, which I recognise I may eventually have to do. Also at the moment I'm having to use the VGA output to debug this because the serial output is halting prematurely, e.g. it shows "a" whilst the VGA shows "a + b c" - is there anything I can do about this? Thanks for your time, Tom Best wishes, Tom Edited 2021-03-09 21:52 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 3998 |
I think the serial O/P is buffered. You can wait for the char(s) to go out. Not sure you can do it from a CSUB - oh, of course you can now that you can call any Basic. Worst case LOF() will do. John |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
Based on wild speculation and little or no knowledge I suspect that the Global Offset Table isn't present/accessible for code in a CSUB and the code is crashing when trying to access the GOT to retrieve/calculate the value to be assigned to the function pointer. Definitely well above my current pay grade ![]() Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10067 |
Does it still hang without the & ? John is correct about the serial output - you can use uSec(n) to wait after output to allow it to complete Edited 2021-03-09 23:18 by matherp |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4251 |
Yes, the &, not-& thing is a red-herring. I've read enough posts on the internet to believe that a standard complier C compiler doesn't care and generates the same code whichever you do. I'm reasonably confident the problem is the lack of the GOT and if that is solveable at all then I imagine it will require someone who really understands THUMB assembler, elf files, etc. and can use that knowledge to extend the CSUB generation code ... ... though I'm very open to someone demonstrating to me that I'm wrong. Thanks to both of you, that at least resolves that issue. Best wishes, Tom Edited 2021-03-09 23:48 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
GerryL Newbie ![]() Joined: 24/01/2019 Location: AustraliaPosts: 36 |
Hi Tom, re finding address of a function and then calling the function via a pointer, this is a bit untidy but works on my CMM2. #include "ARMCFunctions.h" void p_int(int a,int base){ char b[64]; IntToStr(b,a,base); MMPrintString(b); } void GetRetAdd(unsigned int* padd) { // get return address in foo *padd = (unsigned int) __builtin_return_address (0); } void foo(unsigned int* padd, char cInitAdd) { if(cInitAdd){ // initialise the address GetRetAdd(padd); } else{ // what you really want to do in foo() putConsole('*'); putConsole('\r'); putConsole('\n'); } } void main(long long int *c, MMFLOAT *b){ unsigned int* padd = 0; void (*fptr)(unsigned int* , char ); putConsole('a'); putConsole('\r'); putConsole('\n'); foo(padd,1); // *** initialise address putConsole('b'); putConsole('\r'); putConsole('\n'); *padd -= 24; // *** 24 = number of bytes from calling GetRetAdd() in foo to foo's entry // so now data in padd points to foo fptr = (void (*)(unsigned int* , char )) *padd; // *** set pointer putConsole('c'); putConsole('\r'); putConsole('\n'); fptr(padd,0); // call foo via function pointer to do real stuff putConsole('d'); putConsole('\r'); putConsole('\n'); fptr(padd,0); // just to prove it works again! putConsole('e'); putConsole('\r'); putConsole('\n'); } assembly listing of foo showing the 24 bytes, line 134 (address 0000) is entry, end of line 151 (address 0x0014 +4 bytes) is the return address of function GetRetAdd() 15: **** void foo(unsigned int* padd, char cInitAdd) { 130 .loc 1 15 45 131 .cfi_startproc 132 @ args = 0, pretend = 0, frame = 8 133 @ frame_needed = 1, uses_anonymous_args = 0 134 0000 80B5 push {r7, lr} 135 .cfi_def_cfa_offset 8 136 .cfi_offset 7, -8 137 .cfi_offset 14, -4 138 0002 82B0 sub sp, sp, #8 139 .cfi_def_cfa_offset 16 140 0004 00AF add r7, sp, #0 141 .cfi_def_cfa_register 7 142 0006 7860 str r0, [r7, #4] 143 0008 0B46 mov r3, r1 144 000a FB70 strb r3, [r7, #3] 16 if(cInitAdd==1){ // initialise the address 145 .loc 1 16 4 146 000c FB78 ldrb r3, [r7, #3] @ zero_extendqisi2 147 000e 012B cmp r3, #1 148 0010 03D1 bne .L6 17: GetRetAdd(padd); 149 .loc 1 17 3 150 0012 7868 ldr r0, [r7, #4] 151 0014 FFF7FEFF bl GetRetAdd(PLT) I'm no C programmer so apologies if this is wrong, but seem logical to me. Gerry |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10067 |
Given your contribution above many of us might disagree ![]() Many thanks for finding and posting this mechanism |
||||
![]() ![]() ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |