Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 01:27 14 Apr 2021 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 1 of 5    
Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 4738
Posted: 07:11pm 04 Jul 2020
Copy link to clipboard 
Print this post

I've managed to make a very initial implementation of CSUBs on the CMM2  

http://geoffg.net/Downloads/Maximite/CMM2_Beta.zip

Because of limitations on command slots I can't implement CSUBs and CFunctions so I have chosen the former as parameters are always passed by reference so a CSUB can return an answer and in any case MMBasic functions don't support arrays as return values which is likely one of the major uses of CSUBs.

To use the Cfunction you need to install the GCC ARM compiler

I'm using gcc-arm-none-eabi-9-2020-q2-update-win32.exe

The commands for compiling and linking are:



You need the linker file

arm-gcc-link.zip

You then need to convert the .elf file to the Basic code. I'm doing this using a MMBASIC for DOS program

armcfgenV142.zip

As with the PIC there are two variants for the conversion merge and join. Use merge if you need one C function to call another in which case the entry is always to main{}. Use join if the c function is self contained (read the PIC docs for more info)

I have developed a first cut header file that allows the CSUB to call some internal firmware routines - same concept as the PIC

ARMCFunctions.zip

Below is my test C source and test programs. The GCC compiler will give warnings as we are using main{} in a non-standard way. You can convert the the code as either joined, in which case each function can be called separately, or merged, in which case the call is to main{}

First tests appear to suggest that floats can be used as CFunction parameters - this is much better than the situation on the PICs. Of course it is up to the programmer to make sure the C code matches the calling Basic in terms of parameters. If you are new to CFunctions and CSubs then read the various tutorials I posted.

There has been no testing so far of the structure used in the PICs for defining and using constant data.

WARNING: CSUBs are extremely difficult to debug and can crash and even overwrite the firmware - buyer beware!

#include "ARMCFunctions.h"
/*
* This CFunction will reverse the characters in an MMBasic string
* eg if the string is "ABCDEFG" then on return the string will
* be "GFEDCBA"
*/
void strrev(unsigned char in[], unsigned char out[]) {

   unsigned int i;

   unsigned int len;

   //MMBasic stores the length of the string in the
   //first,0th,byte
   len=in[0];

   //Set the length of the output string
   out[0]=len;

   //Do the reverse copy
   for(i=1;i<(len+1);i++){
       out[i]=in[len-i+1];
   }

   //and return the length of the string
}

void waitabit(long long int *w){
uSec(*w);
}
void doubleit(long long int *c, long long int *b){
char a[10];
IntToStr(a,*c,10);
MMPrintString(a);
putConsole(13);
putConsole(10);
*b= *c + *c;
}

void main(long long int *c, long long int *b){
char a[10];
doubleit(c,b);
IntToStr(a,*c,10);
MMPrintString(a);
putConsole('X');
putConsole(13);
putConsole(10);
}



a%=7
b%=2
test a%,b%
print b%
end
CSUB test
0000003A
'strrev
B085B480 6078AF00 687B6039 60BB781B B2DA68BB 701A683B 60FB2301 68BAE00D
1AD368FB 687A3301 6839441A 440B68FB 701A7812 330168FB 68BB60FB 68FA3301
D3EC429A BF00BF00 46BD3714 7B04F85D 00004770
'waitabit
B082B580 6078AF00 681B4B06 687B4619 2300E9D3 46184613 BF004788 46BD3708
BF00BD80 080002A0
'doubleit
B089B5F0 6078AF02 4B156039 461E681B E9D3687B F1072300 200A010C 46089000
4B1047B0 461A681B 030CF107 47904618 681B4B0D 4798200D 681B4B0B 4798200A
E9D3687B 18942300 0503EB43 462B4622 E9C16839 BF002300 46BD371C BF00BDF0
080002C4 080002C0 080002A4
'main
B089B590 6078AF02 68396039 F7FF6878 4B11FFC1 461C681B E9D3687B F1072300
200A010C 46089000 4B0C47A0 461A681B 030CF107 47904618 681B4B09 47982058
681B4B07 4798200D 681B4B05 4798200A 371CBF00 BD9046BD 080002C4 080002C0
080002A4
End CSUB


CSUB doubleit
00000000
B089B5F0 6078AF02 4B176039 461E681B E9D3687B F1072300 200A010C 46089000
4B1247B0 461A681B 030CF107 47904618 681B4B0F 47982058 681B4B0D 4798200D
681B4B0B 4798200A E9D3687B 18942300 0503EB43 462B4622 E9C16839 BF002300
46BD371C BF00BDF0 080002C4 080002C0 080002A4
End CSUB
a%=3
b%=7
doubleit a%,b%
print "b=";b%
end
 
abraxas
Regular Member

Joined: 16/06/2020
Location: Canada
Posts: 99
Posted: 09:05pm 04 Jul 2020
Copy link to clipboard 
Print this post

Yes, Yes, Yes!!!

I mean, Thank You, Peter this is awesome!
 
abraxas
Regular Member

Joined: 16/06/2020
Location: Canada
Posts: 99
Posted: 10:08pm 04 Jul 2020
Copy link to clipboard 
Print this post

Also, the biggest issue I see with this is that with CSUBs, Mauro Xavier will somehow figure out how to run Crysis on this thing and make our efforts look lame in comparison  
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 1312
Posted: 10:17pm 04 Jul 2020
Copy link to clipboard 
Print this post

  abraxas said  Also, the biggest issue I see with this is that with CSUBs, Mauro Xavier will somehow figure out how to run Crysis on this thing and make our efforts look lame in comparison  


I welcome the addition with exactly the same reservations.

Thank you Peter.

Tom
CMM2 Welcome Tape, Z-MIM: Zork on the CMM2
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 482
Posted: 11:21pm 04 Jul 2020
Copy link to clipboard 
Print this post

Hi Peter,
Good result.
A thought about saving some tokens. Is there a possibility
Define Font, End Font, CSUB ,END CSUB, CFUNCTION ,END CFUNCTION
could all share the same token. They all have similar format when stored, only ever happen in pairs and are never nested. Whenever the token is encounter another pointer is looked up to see which particular one it is based on which occurrence of the token you are at.  At a minimum could each set share its start and end token, if you get the token a second time you know it must be an END.

Just thinking about possibility of future CSUBs for the H7.

Regards
Gerry
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 4738
Posted: 11:41am 05 Jul 2020
Copy link to clipboard 
Print this post

I'm really happy with the way CSUBs are working out. The structures for constant data work as per the PIC and floating point just works - much better than the PIC. NB: you cannot use standard C library calls so things like strcpy will need coding into your program. The source of all the standard libraries is widely available online

My latest test program needs a tiny firmware change to add FloatToStr to the list of internal functions supported by the CMM2 firmware but I'll be going through this list in the next days to add lots of stuff. These also have to go into the header file that you use to complie.

Note, the getFPC function is very slightly different from the PIC in that the address has a 1 subtracted. This is a feature of the ARM processor. Functions are called with an address that isn't on a 32-bit word boundary but 1 byte offset. This is some internal mechanism which tells the processor which instruction set to use. In our case this is the Thumb instruction set.

Minor revision to the complilation options to get rid of the warning on main

arm-none-eabi-gcc -c -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -Wall -Wno-main -ffunction-sections -O0 -fPIC -I. main.c -o main.o
arm-none-eabi-ld -nostartfiles -T arm-gcc-link.ld -o main.elf main.o



/*
* This CFunction will reverse the characters in an MMBasic string
* eg if the string is "ABCDEFG" then on return the string will
* be "GFEDCBA"
*/
#include "ARMCFunctions.h"
void strrev(unsigned char in[], unsigned char out[]) {

   unsigned int i;

   unsigned int len;

   //MMBasic stores the length of the string in the
   //first,0th,byte
   len=in[0];

   //Set the length of the output string
   out[0]=len;

   //Do the reverse copy
   for(i=1;i<(len+1);i++){
       out[i]=in[len-i+1];
   }

   //and return the length of the string
}

void waitabit(long long int *w){
uSec(*w);
}
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 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);
}




Edited 2020-07-05 23:30 by matherp
 
abraxas
Regular Member

Joined: 16/06/2020
Location: Canada
Posts: 99
Posted: 09:48pm 07 Jul 2020
Copy link to clipboard 
Print this post

Is there a way to call any form of BLIT form within a CSUB? There is no BLIT provided in the ARMCFunctions.h header.

If not available what's the most efficient way to copy a block of pixels from one video page to another?
 
Sasquatch

Senior Member

Joined: 08/05/2020
Location: United States
Posts: 235
Posted: 12:08am 08 Jul 2020
Copy link to clipboard 
Print this post

  abraxas said  Is there a way to call any form of BLIT form within a CSUB? There is no BLIT provided in the ARMCFunctions.h header.

If not available what's the most efficient way to copy a block of pixels from one video page to another?



Take a look at ReadBufferFast(),DrawBufferFast() and MoveBuffer() in the latest version of ARMCFunctions.h
-Carl
 
MauroXavier
Senior Member

Joined: 06/03/2016
Location: Brazil
Posts: 273
Posted: 11:33am 08 Jul 2020
Copy link to clipboard 
Print this post

  abraxas said  Also, the biggest issue I see with this is that with CSUBs, Mauro Xavier will somehow figure out how to run Crysis on this thing and make our efforts look lame in comparison  

I appreciate your comment  

Crysis not, but who knows Doom? Or even Quake if I didn't have a job  

Joking apart, I intent to port the Wolfenstein 3D at maximum using only MMBasic until my patience comes to the limit, then I will see something with the CSUBs if the performance proves to be unsustainable at all.

I'm thinking how CSUBs can enhance the raycasting without rewrite a big part of the code because what turns it slow in MMBasic is the excessive loop count.

If I rewrite all the loops then practically I'm making a C port of a raycasting engine with MMBasic running only the game core logic, which is not my purpose.

My goal is to any user touch the code and learn with it (even though it is considered complex), and C language with compiling involved (If anyone wants to change something) can put away the beginners, and mainly, kills that famous phrase "it's made only in BASIC?".

For sure I will use CSUBs, but I will hold my will for a while.
 
abraxas
Regular Member

Joined: 16/06/2020
Location: Canada
Posts: 99
Posted: 03:47pm 08 Jul 2020
Copy link to clipboard 
Print this post

I have the same reservations about CSUBs in their present state:

- it's no longer pure BASIC so bragging rights are dimminished
- CSUBs are even more opaque than ASM blocks in BASIC code thus harder for anyone to learn from the code
- I'd rather if MMBasic had an option to compile or JIT the running code instead


That said, the 10x or so speed up might be tempting whenever one hits a performance limit that seems unsurmountable otherwise.

But if all you're doing is coding in C and then uploading to Maximite with just a thin MMBasic wrapper around the CSUB where's the fun in that?
 
Sasquatch

Senior Member

Joined: 08/05/2020
Location: United States
Posts: 235
Posted: 04:24pm 08 Jul 2020
Copy link to clipboard 
Print this post

  abraxas said  I have the same reservations about CSUBs in their present state:

- it's no longer pure BASIC so bragging rights are dimminished
- CSUBs are even more opaque than ASM blocks in BASIC code thus harder for anyone to learn from the code
- I'd rather if MMBasic had an option to compile or JIT the running code instead


I think you make some valid points!  Here are my thoughts:

1.  Keep in mind that CSub code is essentially an ASM block reduced to hexidecimal OP-codes.  It just isn't in a mnemonic form that is more easily human readable.  CSubs are usually small and the source code might be included as a comment block in the .bas file where it is used. Granted this is not as convenient as compiling or assembling the code inline.

2.  MMBasic itself is compiled C code and somewhat "opaque" to the user. (although the source code is available)  Perhaps it might be better to think of a CSub as an extension of the MMBasic environment.  For performance reasons, MMBasic is out of tokens for new features that might be added otherwise, CSubs can fill the gap in some special cases where extreme performance is needed.

  Quote  
That said, the 10x or so speed up might be tempting whenever one hits a performance limit that seems unsurmountable otherwise.

But if all you're doing is coding in C and then uploading to Maximite with just a thin MMBasic wrapper around the CSUB where's the fun in that?


To each his own!  I am happy to have the ability to use a CSub if needed.  I feel it may also open up a new world of possibilities to those who wish to learn something new.
-Carl
 
CircuitGizmos

Guru

Joined: 08/09/2011
Location: United States
Posts: 1354
Posted: 05:11pm 08 Jul 2020
Copy link to clipboard 
Print this post

  abraxas said  
But if all you're doing is coding in C and then uploading to Maximite with just a thin MMBasic wrapper around the CSUB where's the fun in that?


The point of the CSUB capability isn't as much for writing a full program as it is for adding timing-sensitive or speed-improving code to the MMBasic program that is being written.

For example I have to interface a Glonk 6000 retro-encabulator to the 'mite. Writing it in BASIC is tough because of some timing issues. So I write basically a "driver" in C and build a CSUB. Then the rest of the code is written in MMBasic. Other people can use the CSUB driver for their own code.

CSUB isn't meant for everyone using the CMM2 to be able to create/write, but can be used by anyone that needs the result.
Micromites and Maximites! - Beginning Maximite
 
abraxas
Regular Member

Joined: 16/06/2020
Location: Canada
Posts: 99
Posted: 05:25pm 08 Jul 2020
Copy link to clipboard 
Print this post

  CircuitGizmos said  
  abraxas said  
But if all you're doing is coding in C and then uploading to Maximite with just a thin MMBasic wrapper around the CSUB where's the fun in that?


The point of the CSUB capability isn't as much for writing a full program as it is for adding timing-sensitive or speed-improving code to the MMBasic program that is being written.



Yeah, that I know. The slight trepidation is that it might be tempting for the more competitive folks to write the bulk of performance sensitive code in a CSUB thus nullifying all the fun of working on a simple self contained computer.

That said, I'm not at all against having them. In fact I'm really grateful they've been added by Pete although I'd be even happier if they were available on a "pure" Maximite i.e. without a cross compiler sitting on a separate PC getting involved. The pinnacle would be the ability to edit a .C file in the Maximite editor and have a command to generate the ELF bytecode right there on the Maximite with the ability to paste into your .bas code. The friction of CSUBs is currently their biggest drawback in my opinion.
Edited 2020-07-09 03:28 by abraxas
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 2354
Posted: 07:17pm 08 Jul 2020
Copy link to clipboard 
Print this post

  abraxas said  The pinnacle would be the ability to edit a .C file in the Maximite editor and have a command to generate the ELF bytecode


It's not ELF bytecode.  It's Arm ASM (in binary), i.e. you'd need a C-to-Arm-binary compiler, one that's not hosted on any OS (as there isn't one).

Doable but not easy.  Don't hold your breath for it becoming available.

John
 
abraxas
Regular Member

Joined: 16/06/2020
Location: Canada
Posts: 99
Posted: 07:24pm 08 Jul 2020
Copy link to clipboard 
Print this post

Hmm... not sure why you recon that's not easy. As long as there is a CC compiler on the Maximite it should be quite simple to create a command that invokes it on a .CC file on the SSD. The output of CC will be a .obj file which could be statically linked with whatever necessary dependencies the CSUB is pulling. Then it's just a matter of converting the hex data from the compiler to a string of chars.

Yes, I misspoke I know it's just ARM machine code and not bytecode like in a JVM or CLR. I just misspoke - I actually meant ARM binary code.

Doesn't really change my line of thinking though. As long as it's possible for the CMM2 firmware to bundle in a C compiler and a linker (even if it's hidden to us, CMM2 users) it's entirely possible to run it on the Maximite without having to have an x86 PC involved.

So the workflow would be like:
1. you start your Maximite
2. you edit a mycsub.c file
3. you save mycsub.c file and get out of the editor
4. on the command line you issue something like MAKECSUB mycsub.c
5. step 4 outputs mycsub.inc file that looks like this:

CSUB mycsub arg1 as Integer, arg2 as String
9548 8576 3987 ....
END CSUB

6. You use mycsub.inc as any other .inc file in MMBasic

What kind of problems am I overlooking?
Edited 2020-07-09 05:32 by abraxas
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 4738
Posted: 07:49pm 08 Jul 2020
Copy link to clipboard 
Print this post

  Quote  As long as it's possible for the CMM2 firmware to bundle in a C compiler and a linker

Its not and never will be. Way to big for the available memory
 
abraxas
Regular Member

Joined: 16/06/2020
Location: Canada
Posts: 99
Posted: 07:54pm 08 Jul 2020
Copy link to clipboard 
Print this post

  matherp said  
  Quote  As long as it's possible for the CMM2 firmware to bundle in a C compiler and a linker

Its not and never will be. Way to big for the available memory


Yeah, that is a showstopper for sure. Unless you used something like the Tiny C Compiler.

I assume perhaps wrongly that you can still use gcc to develop the firmware but bundle TCC into the firmware? C symbols are ANSI standardised, right? TCC is allegedly only around 100KB in size.
 
MauroXavier
Senior Member

Joined: 06/03/2016
Location: Brazil
Posts: 273
Posted: 08:53pm 08 Jul 2020
Copy link to clipboard 
Print this post

  abraxas said  Yeah, that I know. The slight trepidation is that it might be tempting for the more competitive folks to write the bulk of performance sensitive code in a CSUB thus nullifying all the fun of working on a simple self contained computer.

I'm not worried about "competition" as for me the CMM2 is a hobby and I see a good community born around it. If anyone will use a CSUB to make incredible things, I respect it, but for me isn't pure BASIC anymore.

For me the most fun part of the CMM and CMM2 that it is always a self-contained computer. I use a PC only for editing images and sounds, the rest I used only the editor since the first CMM.

As I said before, the CSUB inserts new possibilities and maybe is a must for some programmers, but as my purpose is to make cool games and demos only in BASIC, opening a world to beginners learn with the code, I will close the CSUB in my toolchains.
 
abraxas
Regular Member

Joined: 16/06/2020
Location: Canada
Posts: 99
Posted: 09:03pm 08 Jul 2020
Copy link to clipboard 
Print this post

  MauroXavier said  
  abraxas said  Yeah, that I know. The slight trepidation is that it might be tempting for the more competitive folks to write the bulk of performance sensitive code in a CSUB thus nullifying all the fun of working on a simple self contained computer.

I'm not worried about "competition" as for me the CMM2 is a hobby and I see a good community born around it. If anyone will use a CSUB to make incredible things, I respect it, but for me isn't pure BASIC anymore.

For me the most fun part of the CMM and CMM2 that it is always a self-contained computer. I use a PC only for editing images and sounds, the rest I used only the editor since the first CMM.

As I said before, the CSUB inserts new possibilities and maybe is a must for some programmers, but as my purpose is to make cool games and demos only in BASIC, opening a world to beginners learn with the code, I will close the CSUB in my toolchains.


Would it change your mind if CSUBs worked in the way I described in my reply to JohnS here?
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 1312
Posted: 09:33pm 08 Jul 2020
Copy link to clipboard 
Print this post

  abraxas said  As long as it's possible for the CMM2 firmware to bundle in a C compiler and a linker ...


This is just idle stirring of the pot ...

Why would this have to be in the firmware? If you have the skills and tenacity then the compiler and linker could be written in BASIC with or without CSUBs as you desire. However in general people don't just knock up a C compiler overnight and as yet nobody has volunteered ... and no, I'm not looking at you Peter, you should kick-back and enjoy your laurels.

The addition of CSUBs offers other possibilities. I believe a FORTH or for that matter Z-machine interpreter could be implemented in the form of a CSUB and embedded in a BASIC program and used to run code faster than interpreted BASIC alone without the need to supply ARM machine-code.

If you want something editable inline with BASIC (and you don't want a pre-processing or transcompiling step) then I would imagine it would probably need a very simple syntax and ~1:1 relationship with ARM machinecode so that the compiler/assembler could be squeezed into the firmware, i.e. either (a subset of) ARM assembler itself or some "made up assembler-like" language. Also given that MMBasic is already pushing on its design limit in terms of number of tokens and other complexity you would probably end up having to do a significant rewrite with all the problems with compatibility and adoption that would entail.

Peter if you are reading this is there any significant space left for firmware or is it tinkering room only? the answer to that might close down the conversation pretty quickly.

Regards,

Tom
Edited 2020-07-09 07:34 by thwill
CMM2 Welcome Tape, Z-MIM: Zork on the CMM2
 
     Page 1 of 5    
Print this page
© JAQ Software 2021