Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Projets de programmation


Index du Forum » Projets de programmation » prog-tools add-in for programming on CG50
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

prog-tools add-in for programming on CG50

Posté le 05/04/2025 18:42

I've been working on an add-in to do programming on the CG50. It has tabs like tmux, and each tab can be split once either vertically or horizontally allowing for up to 12 programs to run at once. Only the currently selected program runs until you switch to another tab or split. I think this will work better than the way the built-in Python does it where you have to save the file and lose your place every time you want to run something.


Each of the 12 splits has its own memory in the 2MB of RAM starting at 0x8c200000. When you start a program or move back to a program that's already running, the add-in shifts the memory for the selected program to the top of the heap so it's contiguous with the rest of the free memory and easy to expand.

I'm close to being finished with a simple shell so I can manipulate files without having to leave the add-in. Thanks to LephenixNoir for the help with file system operations and everything else. I plan to add a Forth interpreter next to write programs that run on the calculator.

I made a small framework with SDL2 for testing the add-in. It configures the video memory the same as the CG50 so writing a pixel there works exactly the same as on the calculator. It reimplements some of the gint functionality too so I can compile the add-in for linux which is very convenient for testing.

I'll add some more information as I finish more features. Please let me know if you have any suggestions! GitHub repo here.


Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 28/04/2025 17:50 | #


The calculator shell is finished now and supports these commands: cat, cd, clear, cp, exit, help, ll, ls, mkdir, mv, rm, rmdir and touch. I started on the Forth interpreter and a little over half of the words (ie functions or commands) I have planned are working.


Forth usually has one large area of memory called the dictionary where global variables, arrays and compiled words (ie functions) are stored. The user can read and write any address as in C or assembly so it's possible to accidently write outside of the dictionary or write data over compiled code and cause a crash. Since this Forth is running on a calculator, I made a few changes so that crashing should be impossible. Addresses used for reading and writing dictionary data start at 0 and refer to the beginning of the dictionary rather than the actual address of the dictionary in memory. Those addresses are masked before each read and write so access is guaranteed to be within the bounds of the dictionary. The data stack is also masked and wraps in the same way so there can be no crashes from underflow or overflow. Masking also prevents alignment problems since the bottom bits can be cleared for 32 and 16 bit accesses to round addresses down. Compiled words are stored in a separate part of memory so there's no way for the use to accidentally change them.
Lephenixnoir Hors ligne Administrateur Points: 25210 Défis: 174 Message

Citer : Posté le 28/04/2025 18:33 | #


I just need to say this UI is gorgeous. @^@
Mon graphe (28 Janvier): (MPM ; serial gint ; (Rogue Life || HH2) ; PythonExtra ; ? ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Yannis300307 Hors ligne Membre Points: 318 Défis: 4 Message

Citer : Posté le 28/04/2025 19:05 | #


Wow impressive work! The project is amazing and so useful for system management tasks!
Développeur sur calculatrice mais qui, contre toutes attentes, prend des douches
Bianxy Hors ligne Membre Points: 1 Défis: 0 Message

Citer : Posté le 30/04/2025 17:09 | #


It's very cool. May I ask when the release of fx-cg50 can be released?
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 01/05/2025 22:56 | #


Thanks a lot!

Bianxy a écrit :
It's very cool. May I ask when the release of fx-cg50 can be released?
There's a still a lot of work left to do. You can try the current version in the root directory of the GitHub page.
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 20/05/2025 22:36 | #


Small progress update - the Forth interpreter can now define words and run them. Unlike most Forths, a word can include references to words that don't exist yet (ie word b in the screenshot) and define them later. Also, redefining a word changes all references to the word (ie word a below) not just new occurrences of it.

Lephenixnoir Hors ligne Administrateur Points: 25210 Défis: 174 Message

Citer : Posté le 20/05/2025 22:41 | #


Is the retroactive nature of redefining names standard? I'm used to having the opposite so one can create closures and ensure they're not modified later by accident.

Edit: Like otherwise if you want a complex word you need to remember all of the sub-words to not accidentally override any.
Mon graphe (28 Janvier): (MPM ; serial gint ; (Rogue Life || HH2) ; PythonExtra ; ? ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 20/05/2025 22:58 | #


No, all the Forths I've seen have it the other way around where you can reuse the name for something else. I can see why that might be useful, although I've never used that functionality for anything myself. I like saving memory when working interactively, and I like how globals work in Python. One use for the standard behavior is using a global variable in one word like a local variable then reusing the same name as a local in another word. I plan to add local variables, so the standard behavior isn't really needed for that. Supporting closures is a good idea. I may implement :NONAME for that situation.
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 30/05/2025 15:45 | #


Lephenixnoir a écrit :
Edit: Like otherwise if you want a complex word you need to remember all of the sub-words to not accidentally override any.

Ya, good point. There is SMUDGE to make a word invisible, but then you would have to remember to smudge all the sub-words. I think it would be good to add a word like IMMEDIATE that makes the last defined word overwritable or have an alternative to : like S: that marks it overwritable when it's defined.
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 09/06/2025 06:04 | #


Latest update - added IF/THEN, BEGIN, DO/LOOP, strings, and a few other things. This totals 125 of the 150 or so words I had planned, so getting toward the end. An empty loop from 0 to 5,000,000 takes about a second, so it should be much faster than Basic.

One thing of note is that I changed the keys around a little bit which greatly adds to quality of life. The biggest improvement is dedicating the (-) key to be space whether alpha is enabled or not so you're not constantly switching in and out of alpha mode to type spaces. Also, pressing alpha twice turns on alpha lock and shift+alpha switches between upper case and lower case.

Mb88 Hors ligne Rédacteur Points: 1260 Défis: 3 Message

Citer : Posté le 09/06/2025 14:42 | #


Druzyek a écrit :
The biggest improvement is dedicating the (-) key to be space whether alpha is enabled or not so you're not constantly switching in and out of alpha mode to type spaces. Also, pressing alpha twice turns on alpha lock and shift+alpha switches between upper case and lower case.


That's interesting. Have you also tried switching between shift or alpha just by checking if the key is pressed down, in a similar way as input in the PythonExtra console works? Personally I found that it made inputting text way faster than having to go in and out of a mode (but it requires using 2 hands).
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 11/06/2025 16:36 | #


Thanks for the suggestion. I gave PythonExtra a try, and that is also a good way to do it. I'll keep working and see which way makes more sense.
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 24/06/2025 07:22 | #


Latest progress:
- New words: LEAVE, EXIT, QUIT, MOVE, EXECUTE
- Added libprof to measure the run-time of the last secondary executed from the prompt. The result can be fetched with PERF.
- Got sh gcc 15.1.0 running in a Docker container so I can test using tail-call recursion with __attribute__((musttail)) to improve performance. The one C file with Forth primitives is compiled to assembly with this newer gcc and the assembly file is passed to fxsdk.

I have a lot of ideas for improving speed and decided to use N queens as a benchmark. My first attempt at a Forth version works but is not especially elegant. With printing the results as shown in the screenshot, the calculator takes 22 seconds for 8 queens (the screenshot is from the PC version so only took 785ms). Without printing the results, the calculator only takes 668ms! This seems like a good start and I can start optimizing trying to lower that number.



4 constant col-size
col-size cells constant col-size-bytes
variable N
variable index
create array
0 cells constant row
1 cells constant A
2 cells constant B
3 cells constant C

: init dup N ! 1 + col-size-bytes * dup allot array swap erase 1 index ! ;
: col col-size-bytes * array + ;
: check-helper + 2dup @ and if 2drop false else swap over @ or swap ! true then ;
: check-A dup row + @ 1 swap lshift swap A check-helper ;
: check-B dup row + @ index @ + 1 swap lshift swap B check-helper ;
: check-C dup row + @ index @ - N @  + 1 swap lshift swap C check-helper ;
: check dup check-A if dup check-B if check-C exit then then drop false ;
: found? index @ N @ = dup if 1 col N @ 0 do dup @ . col-size-bytes + loop drop cr then ;
: next-col index @ dup dup 1 + col swap col over col-size-bytes move 0 swap ! 1 + index ! ;
: inc-col index @ dup col begin over 0 = if 2drop true exit then dup @ 1 + dup N @ =
    if drop swap 1 - swap col-size-bytes - else swap dup dup col-size-bytes - swap col-size-bytes move
    ! index ! false exit then again ;
: queens init begin index @ col check if found? if inc-col else next-col false then else inc-col then until ;

8 queens
Lephenixnoir Hors ligne Administrateur Points: 25210 Défis: 174 Message

Citer : Posté le 24/06/2025 08:12 | #


Nice! I'm not sure musttail will have an effect on performance however. GCC has always done tail call recursion when available. From what I can read musttail will report an error if GCC cannot tail-call the return but it's not obvious whether additional measures will be taken to create a tail call if it wasn't there previously. Keep us in the loop.

For n-queens specifically what algorithm is that? I remember writing the dancing links version and it was pretty bloody fast on computer.
Mon graphe (28 Janvier): (MPM ; serial gint ; (Rogue Life || HH2) ; PythonExtra ; ? ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Druzyek Hors ligne Membre Points: 71 Défis: 0 Message

Citer : Posté le 24/06/2025 20:11 | #


Right, musttail shouldn't have much of an effect by itself. As you mentioned, it should report an error if it can't tail-call which is the behavior I'm hoping for. My current setup is a loop that runs through a list of function pointers to the primitives that make up the program:

void add(struct ForthEngine *engine)
{
    int x=*(engine->sp+1);
    int y=*(engine->sp+2);
    *(engine->sp+2)=x+y;
    engine->sp++;
}

void quit(struct ForthEngine *engine)
{
    engine->executing=false;
}

//Short demo program - add two numbers on stack and exit
void (*program[])(struct ForthEngine *)={&add,&quit};

int execute(struct ForthEngine *engine)
{
    ...
    engine->address=&program;
    while (engine->executing)
    {
        (*engine->address)(engine);
        engine->address++;
    }
    ...
}

Each primitive like add has to return to execute_secondary to increment the function pointer address and check if executing is still true. It would be faster to insert that code at the end of every primitive so it doesn't return to execute_secondary until it's done executing the whole program. As long as all the primitives do the tail call to the next primitive, this will work, but if gcc decides not to do the optimization for one of the 150 primitives then the stack may fill with useless return addresses and cause a crash. I'd rather have musttail throw an error than trust gcc to do the right thing 150 times.

The algorithm is the first one listed on Wikipedia attributed to Wirth where i+j and i-j check for diagonals. I'll have to check out the dancing links version. Some of the Forth examples I saw after I finished were much shorter and used PICK or Forth's return stack. I purposely left out PICK since it's generally not considered good programming practice. I also don't have return stack words like R> and >R to prevent crashes and because abusing the return stack to store values always seemed hacky to me. I'll add local variables soon which should compensate for both of those and shorten the program.

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2025 | Il y a 117 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd