Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 04:24 20 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 : CMM2: V5.05.04b3a: CSUBs - not for the faint hearted!!!!

     Page 4 of 5    
Author Message
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3831
Posted: 10:04am 08 Mar 2021
Copy link to clipboard 
Print this post

  twofingers said  I think what you mean is called "RoutineChecks()".


Thank you, I should have RTFM, it didn't have CSUBs in it when I last read it

Best wishes,

Tom
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
twofingers
Guru

Joined: 02/06/2014
Location: Germany
Posts: 1133
Posted: 10:48am 08 Mar 2021
Copy link to clipboard 
Print this post

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
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8567
Posted: 11:09am 08 Mar 2021
Copy link to clipboard 
Print this post

  Quote  It might be interesting to see how Peter uses it in the source code


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: Germany
Posts: 1133
Posted: 11:26am 08 Mar 2021
Copy link to clipboard 
Print this post

Thanks, Peter, for the explanation!  

Michael
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3831
Posted: 11:55pm 08 Mar 2021
Copy link to clipboard 
Print this post

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
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8567
Posted: 08:01am 09 Mar 2021
Copy link to clipboard 
Print this post

  Quote  Is the use of function pointers within CSUBs not supported?


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 Kingdom
Posts: 3831
Posted: 09:54am 09 Mar 2021
Copy link to clipboard 
Print this post

Thanks for taking the time to reply Peter.

  matherp said  Never tried but I would assume that could be an issue of absolute addressing in a relocatable module.


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.

  matherp said  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.


I did try naively using the same construct as for strings but it didn't work, more research required.

  matherp said  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 wasn't aware, but again I would have thought the compiler/linker should be handling that detail.

  matherp said  I think the first thing will be to look at the generated assembler and see what the compiler is producing.


Fair enough, I'll add it to the list right after learning THUMB assembler - which in truth was on the list anyway.

  matherp said  No easy answers on this one I'm afraid


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
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8567
Posted: 10:27am 09 Mar 2021
Copy link to clipboard 
Print this post

Out of interest you could try

void (*fptr)= foo;
fptr();
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3831
Posted: 10:39am 09 Mar 2021
Copy link to clipboard 
Print this post

  matherp said  Out of interest you could try

void (*fptr)= foo;
fptr();


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
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8567
Posted: 10:45am 09 Mar 2021
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 3831
Posted: 10:49am 09 Mar 2021
Copy link to clipboard 
Print this post

  matherp said  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


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
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3831
Posted: 10:58am 09 Mar 2021
Copy link to clipboard 
Print this post

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
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8567
Posted: 11:11am 09 Mar 2021
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 3831
Posted: 11:46am 09 Mar 2021
Copy link to clipboard 
Print this post

  matherp said  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


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
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3649
Posted: 12:26pm 09 Mar 2021
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 3831
Posted: 01:12pm 09 Mar 2021
Copy link to clipboard 
Print this post

  thwill said  Any bright ideas, other than look at the assembler, which I recognise I may eventually have to do.


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
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8567
Posted: 01:16pm 09 Mar 2021
Copy link to clipboard 
Print this post

  Quote  fptr = &foo; // <--- hangs here, how is that even possible?


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 Kingdom
Posts: 3831
Posted: 01:41pm 09 Mar 2021
Copy link to clipboard 
Print this post

  matherp said  
  Quote  fptr = &foo; // <--- hangs here, how is that even possible?


Does it still hang without the & ?


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.

  matherp said  John is correct about the serial output - you can use uSec(n) to wait after output to allow it to complete


Thanks to both of you, that at least resolves that issue.

Best wishes,

Tom
Edited 2021-03-09 23:48 by thwill
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
GerryL
Newbie

Joined: 24/01/2019
Location: Australia
Posts: 31
Posted: 12:36am 11 Mar 2021
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 8567
Posted: 08:19am 11 Mar 2021
Copy link to clipboard 
Print this post

  Quote  I'm no C programmer


Given your contribution above many of us might disagree  

Many thanks for finding and posting this mechanism
 
     Page 4 of 5    
Print this page
© JAQ Software 2024