|
Forum Index : Microcontroller and PC projects : CSubs: A new (easier) approach
| Author | Message | ||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 11636 |
armcfgen.pdf armcfgen.zip We now have a python script that will compile, link and convert the C source for a CSUB to the basic statements required to run it. Full details of the new approach and how to use it are given in the manual. This is essentially a conversion of armcfgenV144.bas with a number of bugs fixed and a number of enhancements. Specifically, the new version also includes everything needed to allow CSUBs to access constant data defined in the C source - there is an example in the manual AND CSUBs produced in this way and run on PicoMite versions 6.03.00RC22 and above will run on both RP2040 and RP2350 without any changes The zip file contains the python program and the updated header PicoCFunctions.h needed to access the internal firmware functions. These are all described in the manual. An example of the command to create a CSUB would be: python armcfgen.py merge.c --compile -n times3 -e scale3 -O s -I d:\Dropbox\PicoMite\PicoMite This says convert the file merge.c which will need compiling. Name the CSUB times3 and use as the entry point the function scale3, optimise it for size, and find the header file in the directory "d:\Dropbox\PicoMite\PicoMite" For reference below is the csub that works the magic in the bubble universe demo /* bubble.c - "bubble universe" inner loop as a PicoMite CSUB. * * One frame row (66 points): the sin/cos recurrence + scale + offset, producing * integer screen coordinates in c() and d(). Moving this out of the BASIC * interpreter took the demo from 233 ms/frame to ~23 ms. * * Build (compute-heavy -> ask for -Os; -I points at PicoCFunctions.h): * python armcfgen.py bubble.c --compile -n bubblerow -e bubblerow -O s -I <firmware dir> * * Call from BASIC: * CSUB bubblerow INTEGER, INTEGER, FLOAT ' c(), d(), pf() * ... * pf(0)=i : pf(1)=r*i+t * bubblerow c(), d(), pf() * * pf(): 0=iang(i) 1=b(r*i+t) 2=v(state) 3=x(state) 4=pi/2 * 5=xs 6=ys 7=xc 8=yc (v,x persist in pf(2)/pf(3) across calls) * * Uses PicoCFunctions.h: all double maths goes through the firmware CallTable * (Sine/FAdd/FMul/FloatToInt), which the header locates at runtime via VTOR - so * no CallTable argument and no chip-/build-specific address, one blob for every * variant and both chips. (The per-call base re-read the wrappers do is lost in * the noise here - the software Sine calls dominate.) */ #include "PicoCFunctions.h" long long bubblerow(long long *c, long long *d, double *pf) { double iang = pf[0], b = pf[1], v = pf[2], x = pf[3], hp = pf[4]; double xs = pf[5], ys = pf[6], xc = pf[7], yc = pf[8]; int j; for (j = 0; j < 66; j++) { double A = FAdd(iang, v); double siv = Sine(A); double civ = Sine(FAdd(A, hp)); /* cos(i+v) = sin(i+v + pi/2) */ double sx = Sine(x); double cx = Sine(FAdd(x, hp)); /* cos(x) */ double uu = FAdd(siv, sx); v = FAdd(civ, cx); x = FAdd(uu, b); c[j] = FloatToInt(FAdd(FMul(uu, xs), xc)); d[j] = FloatToInt(FAdd(FMul(v, ys), yc)); } pf[2] = v; pf[3] = x; return 0; } Edited 2026-06-21 04:41 by matherp |
||||
| PeteCotton Guru Joined: 13/08/2020 Location: CanadaPosts: 645 |
Wow! This is a great leap forward in simplifying the compilation of CSubs. Thank you ![]() Edited 2026-06-22 04:14 by PeteCotton |
||||
| Bleep Guru Joined: 09/01/2022 Location: United KingdomPosts: 817 |
Hi Peter, I'd really like to give this a try, but I'm away till a week Tuesday, :-( but I'll give it test run asap after that. Regards Kevin. |
||||
| Bleep Guru Joined: 09/01/2022 Location: United KingdomPosts: 817 |
Hi Peter, After tearing my hair out to get the environment set up to be able to compile, I've now got a compile error I don't know how to fix, it seems to be a problem with MOD or %, if I remove it the program compiles, I've tried declaring i as a standard int, just in case, but I still get an error. undefined reference to `__aeabi_ldivmod or _idivmod. I have checked and % is a fundimental part of C, so in theory no extra libraries needed. Any help appreciated. #include "PicoCFunctions.h" long long pixie(double *xsq, double *ysq, double *x0, double *y0, long long *a, long long *mi, long long *c) { long long i; double x=0, y=0; //Do :xsq=x*x:ysq=y*y:y=2*x*y+y0:x=xsq-ysq+x0:Inc i:Loop While xsq+ysq<=4And i<mi //'If i=mi Then:c=0:Else :c=i Mod 15:EndIf //c=(i<mi)*i Mod 15 while((FloatToInt(FAdd(*xsq,*ysq)) <= 4) && (i < *mi)) { *xsq=FMul(x,x); *ysq=FMul(y,y); y=FAdd(FMul(FMul(2,x),y),*y0); x=FAdd(FSub(*xsq,*ysq),*x0); } if(i<*mi) { *c=i % 15; } else { *c=0; } return 0; } Error PS C:\Users\Kevin\pico\mandelcsub> python armcfgen.py pixie.c --compile -n pixie -e pixie -I C:\Users\Kevin\pico\mandelcsub C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/14.2 rel1/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\Kevin\AppData\Local\Temp\tmpo6fktbvd.o: in function `pixie': pixie.c:(.text.pixie+0x168): undefined reference to `__aeabi_ldivmod' collect2.exe: error: ld returned 1 exit status Traceback (most recent call last): File "C:\Users\Kevin\pico\mandelcsub\armcfgen.py", line 274, in <module> main() ~~~~^^ File "C:\Users\Kevin\pico\mandelcsub\armcfgen.py", line 239, in main elf = link(objs, args.entry) File "C:\Users\Kevin\pico\mandelcsub\armcfgen.py", line 198, in link subprocess.run([GCC, "-nostartfiles", "-nostdlib", ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "-Wl,-T," + ld.name, "-Wl,-e," + entry, "-Wl,--no-warn-rwx-segments", ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "-o", elf, *objs], check=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Program Files\Python313\Lib\subprocess.py", line 579, in run raise CalledProcessError(retcode, process.args, output=stdout, stderr=stderr) subprocess.CalledProcessError: Command '['arm-none-eabi-gcc', '-nostartfiles', '-nostdlib', '-Wl,-T,C:\\Users\\Kevin\\AppData\\Local\\Temp\\tmpwhf0biob.ld', '-Wl,-e,pixie', '-Wl,--no-warn-rwx-segments', '-o', 'C:\\Users\\Kevin\\AppData\\Local\\Temp\\tmp4842apy3.elf', 'C:\\Users\\Kevin\\AppData\\Local\\Temp\\tmpo6fktbvd.o']' returned non-zero exit status 1. PS C:\Users\Kevin\pico\mandelcsub> Edited 2026-07-06 06:33 by Bleep |
||||
| disco4now Guru Joined: 18/12/2014 Location: AustraliaPosts: 1133 |
undefined reference to `__aeabi_ldivmod' means you are trying to access a function in __aeabi library which is not available. The MOD function is not available in the CallTable functions. You might be able to do it without 64bit functions as below. i.e. Use the IDiv(a,b) function in the CallTable. //*c=i % ; long long j; j=IDiv(i,15) j=(j<<4)-j //Multiply by 16 (shift left 4) then -j for 15x *c=i-j F4 H7FotSF4xGT |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 11636 |
Assuming I do a maintenance build sometime, I'll include IMod(a,b) as a new function in the header and code. At the moment you will have to use Gerry's method. The IDiv function was added sometime ago for exactly the same reason. |
||||
| Bleep Guru Joined: 09/01/2022 Location: United KingdomPosts: 817 |
Hi, ok thanks for the info. Presumably the good old AI is wrong again, % isn't a fundamental part of C? it's in a math library. :-( Thanks for adding to the function library. Regards Kevin |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 11636 |
The RP chips don't have 64-bit native integer support (the CMM2 chip does). For simple maths like add, subtract and multiply the compiler generates in-line code to execute them. 64 bit divide is more complex so it invokes a library routine. CSUBs do not have access to library routines unless they are in the header file because there is no way for them to know where they are in the current build. |
||||
| disco4now Guru Joined: 18/12/2014 Location: AustraliaPosts: 1133 |
Peter, Is this for long long i.e. 64bit integers or do you need to convert to 32bit int as shown in the example in the PDF manual. long long sqr(long long *a) { int v = (int)(*a); /* 32-bit multiply, avoids __aeabi_lmul */ *a = (long long)(v * v); return 0; } x% = 5 : sqr x% : Print x% ' 25 If GCC also generates code for the long long 64bit integers I don't think the PDF spells this out. F4 H7FotSF4xGT |
||||
| JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 4352 |
Er, % is definitely part of C - but how it's implemented on a particular CPU etc is up for grabs (same as for any other part of C). Happening to call a library function is normal and very much allowed (even if frustrating!). John Edited 2026-07-06 20:46 by JohnS |
||||
| Bleep Guru Joined: 09/01/2022 Location: United KingdomPosts: 817 |
Hi again, Here is a recursive, MMBasic implimentation of a Mandelbrot, using a CSub for the innermost tight loop. It speeds up the calculation from using pure Basic by about 3X or 7X if you don't use TraceCache, I could go further, but for now I just wanted to be able to know how to use CSubs and what the constraints were. :-) It runs best on a VGA screen, but will also work on a LCD, it doesn't scale itself. Regards Kevin. 'Option Base 0 Option Default None Option Explicit 'Option Cache Debug On 'Option Profiling On Option TraceCache On 32 Dim Float y0,x0,x1,y1,x2,y2 'Dim Float x,y,xsq,ysq,xmin=-2.0,xmax=-1.5,ymin=-0.12,ymax=0.12 Dim Float x,y,xsq,ysq,xmin=-2.0,xmax=0.5,ymin=-1.2,ymax=1.2 Dim Integer i,j,k,l,p,pp,c Dim Integer tcx,tcy,bs,nfi,mi=32 Dim Integer col(15)=(0,RGB(0,63,0),RGB(0,127,0),RGB(0,255,0),RGB(0,0,255),RGB(0,63,255),RGB(0,127,255),RGB(0,255,255),RGB(255,0,0),RGB(255,63,0),RGB(255,127,0),RGB(255,255,0),RGB(255,0,255),RGB(255,63,255),RGB(255,127,255),&HFFFFFF) If MM.DEVICE$="PicoMiteVGA" Or MM.DEVICE$="PicoMiteHDMIUSB RP2350B" Then Mode 2 '320x240 PicoMiteVGA EndIf Timer =0 '8,16,32,64,128,256 'CLS RGB(White) bs=256 For j=0 To 239 Step bs tcy=j For k=0 To 239 Step bs tcx=k fil(tcx,tcy,bs-1)',nfi) If nfi Then quarter(tcx,tcy,bs-2) EndIf Next Next Print Timer End Sub quarter(tcx1 As Integer, tcy1 As Integer, bs1 As Integer) Local Integer ss,s1,tx1,ty1 If bs1<3 Then fil(tcx1+1,tcy1+1,1):nfi=0:Exit Sub ' Finished square tx1=tcx1+1:ty1=tcy1+1 ss=(bs1>>1)-1:s1=ss+2 fil(tx1,ty1,ss)',nfi) If nfi Then quarter(tx1,ty1,ss) ' fil(tcx1+s1,ty1,ss)',nfi) If nfi Then quarter(tcx1+s1,ty1,ss) ' fil(tx1,tcy1+s1,ss)',nfi) If nfi Then quarter(tx1,tcy1+s1,ss) ' fil(tcx1+s1,tcy1+s1,ss)',nfi) If nfi Then quarter(tcx1+s1,tcy1+s1,ss) End Sub Sub fil(tx1 As Integer,ty1 As Integer, s As Integer)', nfi As Integer) Local Integer cc,p,pp,cp Local Float x1,y1,x2,y2 x1=xmin+(xmax-xmin)*tx1/239 y1=ymin+(ymax-ymin)*ty1/239 'single pixie If s=1 Then x0=x1:y0=y1:Pixie x0,y0,mi,cp,cc,col():Pixel tx1,ty1,cp:End Sub x2=xmin+(xmax-xmin)*(tx1+s)/239 y2=ymin+(ymax-ymin)*(ty1+s)/239 pp=0:nfi=1 'four sides of a square For p=ty1 To ty1+s x0=x1:y0=ymin+(ymax-ymin)*p/239:Pixie x0,y0,mi,cp,cc,col():If p=ty1 Then cc=cp Pixel tx1,p,cp x0=x2:Pixie x0,y0,mi,cp,cc,col() Pixel tx1+s,p,cp x0=xmin+(xmax-xmin)*(pp+tx1)/239:y0=y1:Pixie x0,y0,mi,cp,cc,col() Pixel tx1+pp,ty1,cp y0=y2:Pixie x0, y0,mi,cp,cc,col() Pixel tx1+pp,ty1+s,cp Inc pp Next If cc>-1 Then p=s-1:Box tx1+1,ty1+1,p,p,,cc,cc:nfi=0'Finished square End Sub 'Sub Pixie 'i=0:x=0:y=0 'Do :xsq=x*x:ysq=y*y:y=2*x*y+y0:x=xsq-ysq+x0:Inc i:Loop While xsq+ysq<=4And i<mi ''If i=mi Then:c=0:Else :c=i Mod 15:EndIf 'c=(i<mi)*i Mod 15 'End Sub CSub PIXIE Float, Float, Integer, Integer, Integer, Integer 00000000 'pixie B08FB5F0 60F8AF00 607A60B9 2200603B 633A2300 2200637B 62BA2300 220062FB 623A2300 4B65627B 331C681B 33A0681B 001C681B 6AFB6ABA 6AF96AB8 000247A0 61BA000B 4B5D61FB 331C681B 33A0681B 001C681B 6A7B6A3A 6A796A38 000247A0 613A000B 4B55617B 331C681B 33A4681B 001C681B 681B4B51 681B331C 681B33A0 4B4E001D 331C681B 33A0681B 001E681B 6AFB6ABA 21802000 47B005C9 6A7B6A3A 68BB47A8 685B681A 000247A0 623A000B 4B42627B 331C681B 33A4681B 001C681B 681B4B3E 681B331C 681B33A8 693A001D 69B8697B 47A869F9 681A68FB 47A0685B 000B0002 62FB62BA 681B4B34 681B331C 681B3388 4B31001C 331C681B 33A4681B 001D681B 697B693A 69F969B8 000247A8 0010000B 47A00019 000B0002 DC182B00 2A04D101 6B3AD815 20016B7B 18122100 633A414B 687B637B 685B681A 42996B79 E770DA00 42996B79 6B39D103 D2004291 687BE769 685B681A 42996B79 6B79DB05 D10E4299 42916B39 6B3BD20B 4013220F 6D7A00DB 681A18D3 6839685B 604B600A 6839E004 23002200 604B600A 68186D3B 683B6859 685B681A D1014290 D0054299 22016D39 17D34252 604B600A 23002200 00190010 B00F46BD 46C0BDF0 E000ED08 End CSub This is the C for the CSub above. #include "PicoCFunctions.h" long long pixie(double *x0, double *y0, long long *mi, long long *cp, long long *cc, long long *col) { long long i=0,c; double xsq,ysq,x=0, y=0; //Do :xsq=x*x:ysq=y*y:y=2*x*y+y0:x=xsq-ysq+x0:Inc i:Loop While xsq+ysq<=4And i<mi //'If i=mi Then:c=0:Else :c=i Mod 15:EndIf //c=(i<mi)*i Mod 15 do { xsq=FMul(x,x); ysq=FMul(y,y); y=FAdd(FMul(FMul(2,x),y),*y0); x=FAdd(FSub(xsq,ysq),*x0); } while((FloatToInt(FAdd(xsq,ysq)) <= 4) && (++i < *mi)); // Set up pixel colour if(i<*mi) { *cp=col[i & 15]; } else { *cp=0; } // Check for colour change if(*cc != *cp) { *cc = -1; } return 0; } 'Use the command line to build, see documentation. 'python armcfgen.py pixie.c --compile -n pixie -e pixie -I C:\Users\Kevin\pico\mandelcsub |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 11636 |
Excellent, glad you got it all to work. Windows, Mac or Linux? |
||||
| Bleep Guru Joined: 09/01/2022 Location: United KingdomPosts: 817 |
For now Windows, because I know that's what you use, so I thought I'd stand a better chance of getting it going, now I 'sort of' know what to do I might give Linux a go, just for a bit of extra punishment. :-( Especially as the rest of this week is looking to be uncomfortably hot.... |
||||
| Bleep Guru Joined: 09/01/2022 Location: United KingdomPosts: 817 |
I've also now tested it on a 2040 with LCD and the above code works without change, in other words the CSub is, as you said, fully compatible with both types of Pico processor. I also tried the steroids version of Bubble Universe on the 2040 & that worked well as well. Thanks again. Regards Kevin. Edited 2026-07-07 22:39 by Bleep |
||||
| The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2026 |