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 » Complete C standard library
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Complete C standard library

Posté le 19/08/2018 19:31

Motivation
Until now there was no complete C standard library (aka libc) available for the Casio calculators. Although some parts of this library have been provided by fxlib and gint, there was no libc implementation complying with the standard and compatible with the sh3eb architecture ready to use.

To change that, I decided to port newlib to the Casio CPU. Newlib is an alternative libc implementation intended for use on embedded systems.


Alpha
Follow this link and click the download button in the top right corner:

>>> v1.1 <<<


Instructions on how to install newlib alongside with gcc (big shout-out to Lephé):

Compiler sous Linux avec GCC


Features for Casio fx9860g calculators:
* C standard library libc
printf implementation to print text to the display
→ Dynamic allocation of memory using malloc and free
→ Memory manipulation using memcpy, memcmp, memset etc.
→ String manipulation using strcpy, strcmp, strstr, strtok
→ ...
* Math library libm
→ Floating point arithmetics
→ ...
* Automatic library and include path recognition after installation
* Basic Casio features:
→ implementation of GetKey, Bdisp_AllClr_DDVRAM, Bdisp_PutDisp_DD, Print and locate without fxlib (but you can use it if you want)


Code
To contribute or get all those bleeding edge features, see the code including all further information:

libc (my GitLab repository)


The project you find in my repository is a fork of the official newlib repository. To make it easier for everyone to follow, I try to keep a clean git history. That means that all my changes are located on a dedicated branch with meaningful commits.

I also try to keep the changes to the upstream library minimal. That increases maintainability a lot.


Contributing
If you have a ideas, feature request, found a bug or simply want to contribute, just send me a message and you're in! You can also create Issues and Merge Requests directly in the repository. As in every OpenSource project: merge requests welcome!


Précédente 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 Suivante
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 04/09/2018 00:15 | #


Ok, so what I formulated in 2) was not quite correct. What I wanted to say is:
Halting the processor is very suboptimal since it produces all the problems you described. It's only of use if you really need to save energy.

There are some justified applications such as:

setTimerTo(5000);      // 5000 ms
sleep();


However, usually, if you need to work with interrupts, you would choose busy waiting:

while (1) {
    setTimerTo(1000);
    // do sth
    while (!timeIsUp);       // busy waiting (instead of sleep)
    // do sth else
}

Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 04/09/2018 08:10 | #


Halting the processor is very suboptimal since it produces all the problems you described. It's only of use if you really need to save energy.

Oh, I see. Sleeping and separating the clock signal from the processor were the same thing for you (which may be factual, I don't know the details tbh).

Well, if you need a few figures to be convinced of the benefits of sleeping; I once wrote a simple clock application (here), it was at a time when no SH4 clock was available. This one would busily wait for the RTC to tick at each second; and it would exhaust the calculator's batteries in a few hours' time.

Though I have not found a proof in the code, I am fairly sure that GetKey() sleeps. This function is what runs 95% of the time when using the system apps and the longevity of the batteries is already a very strong hint.

-

There are other solutions to the "sleeping problem". For example, if you stop considering that there is only one interrupt, or that you can only disable all interrupts at once, you can do the following:

1. Consider two timers regular (which you want to sleep for) and timeout (a helper timer). At the beginning regular is set up with a user-chosen delay and its interrupt is enabled; timeout is disabled.
2. The first code extract from my article is used.
3. Before checking the condition, disable the interrupt for regular.
4. If the condition is false, leave; regular has been disabled automatically already.
5. If the condition holds, configure timeout to fire once, very quickly (≤ 1 ms).
6. Go to sleep.
7. After a short delay, timeout fires; use this to enable the interrupt for regular.
8. Now you're sleeping with the interrupt enabled.

This works only if the interrupt for timeout does not wake up the userland program from its sleep. If think it can be configured to depend on the interrupt priority. I would need to check.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 04/09/2018 17:27 | #


Lephenixnoir a écrit :
Oh, I see. Sleeping and separating the clock signal from the processor were the same thing for you (which may be factual, I don't know the details tbh)

They are definitely not the same and I was just plain wrong.

Lephenixnoir a écrit :
Though I have not found a proof in the code, I am fairly sure that GetKey() sleeps. This function is what runs 95% of the time when using the system apps and the longevity of the batteries is already a very strong hint.

I did not expect that and in this case I take back my argument.

It would be fun discussing this topic in a chat. Apropos, is there a chat beside general and discussion?
Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 04/09/2018 19:14 | #


It would be fun discussing this topic in a chat. Apropos, is there a chat beside general and discussion?

No, there's not; in fact the separation between general and discussion is already recent.

Now that you mention it, there was actually a funny situation with more channels before I set up special urls like /shoutbox/general and /shoutbox/discussion; back then the url was on the form /shoutbox/?channel=x, and any x worked for the script because it served as a channel indicator in the database. When Xavier59 asked whether there were more channels, I said "no" without suspecting a thing, and he quickly proved me wrong by sending messages to a hidden channel no. 63057 whose existence I had not even planned. xD

Since it would be an interesting discussion, you'll want it to be archived, so the chat is not a very good idea. The forum should be more suitable for that, don't you agree?
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 04/09/2018 19:51 | #


Well, I think sometimes it is easier to find out more about a certain topic if a topic is so new, that you do not even know really what questions to ask.

Ajouté le 04/09/2018 à 22:15 :
For example I have a question about the interrupts:

So I imagine there is an interrupt routine for each interrupt which is executed by the CPU even if it was halted before. What happens afterwards? Does the CPU go to sleep again? Can the interrupt know if the CPU was sleeping or not?
Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 04/09/2018 22:27 | #


They are definitely not the same and I was just plain wrong.

I got to check it and you're nowhere close to wrong! This is in fact as good as you can get: documentation says "Sleep mode: Supply of the clock to the CPU core is stopped.".

So when I suggested you may not wake up from that state, I was actually plain wrong.

So I imagine there is an interrupt routine for each interrupt which is executed by the CPU even if it was halted before.

There is only one interrupt routine for all interrupt types; usually this master routine branches to some specialized interrupt handler by checking the INTEVT or INTEVT2 register that uniquely identifies interrupt sources. So from the point of view of the hardware there is only one ISR.

What happens afterwards? Does the CPU go to sleep again?

It depends on how deep the chip is sleeping. In normal sleep mode where the CPU clock is halted, any interrupt or reset will cause the processor to restart execution. In complete standby mode (something like hibernation), you need a reset or one of a few select interrupts such as NMI or keyboard. In our clock configuration, the deepest U-standby mode can only be exited by a reset.

Can the interrupt know if the CPU was sleeping or not?

I don't know of a way.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 05/09/2018 17:33 | #


That's actually very interesting! Since there is no official documentation, where can I find information about this topic?
Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 05/09/2018 17:39 | #


Have a look at the SH7724 documentation. You can conveniently find a copy in TeamFX's gathering of doc, which includes MPU, RAM, Flash, display, MoBo photos, and more. This reference has been called "TeamFX's bible" for quite some time, which is why the following link is to bible.planet-casio.com. Look in the mpu directory.

https://bible.planet-casio.com/hardware/

Now there are other directories and contributed documentation in there, mainly sorted by contributor, don't hesitate to have a look if something piques your interest.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 05/09/2018 18:04 | #


Wow, that is quite some information, thanks!

Ajouté le 05/09/2018 à 20:07 :
Implementing scanf is much harder than I thought... not because the stdlib is so complicated, but because this calculator has too few keys! ...Oh and because the fxlib syscall is really not what I wished it was (key combinations e.g. SHIFT+5)
Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 05/09/2018 20:34 | #


What could be the problem with the keys? You mean not enough keys to input various ASCII characters to the virtual terminal? Well, you have the SHIFT and ALPHA modifiers for this purpose.

Could you explain more precisely what you wished and what it is? Maybe I can point you to something more appropriate.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 05/09/2018 20:38 | #


If you want to add keys to the keyboard (shift+5 as you said, for example) then indeed, GetKey() is not enough. Though I don't know why you'd want to bypass GetKey(), it allows entering all necessary characters (and you can make a [CHAR] menu on F6 for other characters).

What I do with CasioPy is using PutKey(OPTN) to reset the modifier, then keep track of modifiers myself. See https://github.com/Zezombye/casiopy/blob/8330d4de3ba3647b073885d863b3f919ab8b4082/ports/minimal/console.c#L73
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 05/09/2018 20:40 | #


I don't know if you own a Graph 75+ Zezombye, but on this machine SHIFT + OPTN toggles the backlight so you might want to use a key that doesn't have a special behavior on SHIFT... except there's none. >_<
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 05/09/2018 21:07 | #


I actually i have two problems:

1) The technical problem is that I want to use combinations like SHIFT+5 or SHIFT+7 which can not be used via GetKey(). [@Zezombye] Your PutKey() hack is actually a good idea! That might enable me to track all combinations.

2) Another practical problem is that I basically want to provide an intuitive and well usable way of entering all common ascii chars. This is very hard for chars which are not written on the keyboard (especially lower case letters and special symbols: !"§$%&/()=?,\n,\r,\t,...)

The menu for special symbols is a great idea, however I have a very generic function (scanf) and basically no way of explaining to the user, that F6 opens the special menu they need. I consider using the key CATALOG or List, but to be honest I do not like these options either
Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 05/09/2018 21:13 | #


Well, to be honest I do think that performing keyboard and screen input/output in the standard library is a bit harsh. It'd be easier if you had the support of the runtime library.

Have you considered using syscall 0x24a ?

0x24A: int Keyboard_GetPressedKey(short*matrixcode);

This one returns a matrix code, very similar to gint's, so it will definitely not bother you with ALPHA/SHIFT combinations. Feels better than injecting keys to me. Although you'll have to do the waiting yourself but a call to the sleep instruction should be more than enough.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 06/09/2018 13:05 | #


Hmm, that would be even better... but I cannot make it work

Is the signature really the following?

int Keyboard_GetPressedKey(short*);


Unfortunately, my convenient list of fx9860g syscalls does not include the function signature
Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 06/09/2018 13:09 | #


You just need to follow the link (and fix the case typo in it): http://media.taricorp.net/prizm/simon_chm/fx_legacy_keyboard.htm

Now this is indeed the correct signature; I have never used this specific syscall in an add-in but I disassembled various versions of it and I don't remember any mismatch between SimLo's prototype and the actual code.

What exactly are you getting?
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 06/09/2018 13:24 | #


Oh thank you.

There is my (minimal) code:


typedef int (*_get_pressed_key_type)(short* matrixcode);
const unsigned int _get_pressed_key_address[] = { 0xD201D002, 0x422B0009, 0x80010070, 0x24A };
const _get_pressed_key_type _get_pressed_key_ptr = (_get_pressed_key_type) _get_pressed_key_address;

typedef void (*_sleep_type)(unsigned int ms);
const unsigned int _sleep_address[] = { 0xD201D002, 0x422B0009, 0x80010070, 0x420 };
const _sleep_type _sleep_ptr = (_sleep_type) _sleep_address;

int main(void) {
    int i = 0;
    unsigned int key = 0;
    short matrix_key;

    char out[20] = "Test";

    while (1) {
        Bdisp_AllClr_DDVRAM();
        
        sprintf(out, "[%d]  %x", i++, matrix_key);
        locate(3, 4);
        Print("Key: ");
        Print(out);

        Bdisp_PutDisp_DD();
        _get_pressed_key_ptr(&matrix_key);
        _sleep_ptr(1000);
    }

    return 0;
}

Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 06/09/2018 13:44 | #


Ok so I checked my annotated disassembly of this syscall and against all odds, it seems to check that the provided keycode in matrix_code is pressed.

As far as I could test it returns 1 when AC/ON is pressed and 0 otherwise. This corresponds neither to SimLo's description nor to my disassembly, and it's quite weird.

Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 06/09/2018 14:30 | #


Hmm, I think this is not usable for me... I actually do not want to check every key every x milliseconds.

@Zezombye Your solution works like a charm! That's actually a brilliant idea!

@Lephé Switching on the backlight still works.
Stop starting~ Start finishing~
Lephenixnoir Hors ligne Administrateur Points: 24228 Défis: 170 Message

Citer : Posté le 06/09/2018 15:07 | #


This clearly needs investigation. As a very last suggestion, have you tried using the two first parameters of GetKeyWait() ?

Edit: Not that I don't like Zezombye's method, but... well, it's a hack.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Memallox Hors ligne Membre Points: 161 Défis: 0 Message

Citer : Posté le 06/09/2018 15:24 | #


Okok, using the dedicated function works and is actually much cleaner. I'll use GetKeyWait()

Thanks for being the reasonable one here, Lephé.

@Zezombye Your solution is still clever though

Ajouté le 07/09/2018 à 14:31 :
I'm at implementing scanf when suddenly... A very strange problem appears!
I use logic... It's not very effective!

Here is the error I get. Note that I get this error instantly, i.e. without pressing any key before.


System ERROR
REBOOT    :[EXIT]
INITIALIZE:[EXE]
ADDRESS(R)
TARGET=0030080E
PC    =003002E4


Ok, I probably dereference an invalid pointer (which points to ROM)... should be easy to find.
Since I did not press any key before the error appeared, the error must be caused by something before the first call of GetKey(), non?
Let's look at my main:


int main(void) {
    unsigned int key = 0;
    char out[20] = "Test";

    while (1) {
        Bdisp_AllClr_DDVRAM();

        locate(1, 4);
        Print("Out: ");

        Bdisp_PutDisp_DD();
        GetKey(&key);
        _read(0, out, 5);  // <-- when I comment this line out, it works!
    }

    return 0;
}


Ok, first I thought, the new implementation of _read() cannot be the problem. But when I comment it out, it works o.O.
However, _read() only calls _console_read() which instantly returns.

I think the problem is that the linker links much more code if I call _read(). As a consequence, one of the previous calls (locate, Print etc.) fails. That's just a guess, however, and I have not the slightest idea on how to solve such a problem

Stop starting~ Start finishing~
Précédente 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 Suivante

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 - 2024 | Il y a 73 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