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!
Citer : Posté le 23/08/2018 22:04 | #
[...] a good complete, packaged, documented thing, I fail to see.
I'm surprised that there are so many cool applications here and yet not a really solid basis (hardware support, libc etc.). (So good job creating gint xD)
I can't deny dprint() or sprintf() to the non-libc user since I have a lightweight implementation at hand.
Of course not, classical case for #ifndef __NEWLIB_H__
I find the way you elude how hellish USB is, fascinating.
To be honest I never developed apps for USB. Right after I started all those cool ideas that sound much better in my head than they are in reality... and finished them about 60% just to abandon them - I might collaborate with you implementing USB to... (which device do you even want to communicate to? You'd have to write a linux usb driver... That requires a good use case for motivation)
Citer : Posté le 23/08/2018 22:15 | #
Since this is at gint compile-time, where I don't include newlib headers, I'd rather rely on the configuration file. Or do you mean I can decide whether to expose my printf()-family functions at add-in compile time?
Am I wrong assuming that we could communicate with Linux without having to write a new Linux driver?
Honestly the possibilities are vast! Start with a more-automated transfer tool than LINK. Then USB logs for add-ins that may crash before even being able to display anything (... ). And controlling a music player from the calculator to make better sound than the 1-bit serial sound. A GIF/video recorder that does not use protocol 7...
Citer : Posté le 23/08/2018 22:33 | #
Since this is at gint compile-time, where I don't include newlib headers, I'd rather rely on the configuration file
Never mind, I'm an idiot. This is a classical use case of the weak attribute, though. Now for real
Am I wrong assuming that we could communicate with Linux without having to write a new Linux driver?
Frankly I don't know. I expect that we had to write a driver (probably use libusb)...
Ok debugging would be neat. xD
the 1-bit serial sound
Please tell me that the calculator has a beeper integrated!
Citer : Posté le 23/08/2018 22:40 | #
Well spotted!
Totally not, we can either make 1-bit sound using raw serial data, or - using a technique which I attribute to Martin Poupe - spam the serial port so hard that it can't keep up with the 0-5V switches and ends up oscillating somewhere in the middle, allowing the add-in to output an analog signal by varying the relative amount of 0's and 1's in the serial stream to bump the tension up or down. Although the output is at low volume since the oscillation range is slim, I must admit that it works extremely well.
Now I just pushed a simple test to the repository for the test application: it's a somewhat exhaustive test for the core memory functions, memcpy(), memset() and memmove(). It checks that the result is correct for all alignment/overlap scenarios, and does it with different operation lengths to trigger optimization mechanisms.
As expected the result is good: 768/768. However, printf() triggered a SysERROR of type INTERRUPT, which should never happen with reasonable add-ins, so you might want to have a look into it. I also had to define an _end symbol in the linker script to be able to build without interfering with your current work on _sbrk; I hope it won't disturb.
Also, I've had a quick look at the size of the resulting program (35~40k), which is reasonable but quite high. Not sure what we can do about it...
Citer : Posté le 23/08/2018 22:57 | #
A demo of the sound you can get oncalc. The hardware (a capacity) purpose is to improve the quality of the output sound.
Citer : Posté le 23/08/2018 23:29 | #
Cool. I always wondered what the jack at the top right side is good for!
@Lephe A dumb bug again. I didn't notice that the strings passed from printf to write are not null-terminated. Fixed now.
Also, thank you for testing!
About the code size: I'm sure there are configure options to reduce the code size. I'll look into that tomorrow.
Addendum: they can also be set by default for our target to safe the user from typing a hundred frags into the command line.
Citer : Posté le 23/08/2018 23:44 | #
Aye, typical trap, I'd fall into it as well xD
You're welcome! Don't forget to start with -Os since there's pretty much 30k of code in there
Citer : Posté le 24/08/2018 12:30 | #
I disabled some features by default for the sh3eb target now. Lephé, could you add the --enable-target-optspace to the configure call in the Compiler sous Linux avec GCC tutorial, please?
Citer : Posté le 24/08/2018 14:26 | #
Yes, that's done! I also rebuilt my compiler with it, and checked the new size of your add-in : it's about 29k which is at least 5k less than before. A nice improvement!
Citer : Posté le 24/08/2018 14:26 | #
Thanks
Citer : Posté le 29/08/2018 11:25 | #
Hi Memallox, I definitely saw the message you sent me some days ago, but by the time I saw it, I wasn't able to answer very easily… and now that I am, I'm not sure, with what I see on this topic, that I could provide you with anything new anyway… x)
I'm glad to see that this project is pretty well engaged, and I will spend some time giving a more precise look to the git repo and to all that has been said here… !
Citer : Posté le 31/08/2018 14:56 | #
I seems that newlib is not C99 compliant. While it provides all functionality I would expect from a libc implementation at first glance, I noticed that it does not provide the %zu format specifier (which is definitely part of the C99 standard).
int variable = 42;
printf("Size of variable: %zu", sizeof(variable));
// prints "Size of variable: zu" instead of "Size of variable: 4"
After further investigation, there is no claim that newlib is compliant to anything. I guess that's because some functionality is stripped from the library since it is targeted for embedded devices. Do you think that's a problem? We might implement features we desperately need by ourselves. Cakeisalie5 is probably an expert here due to his efforts with libcarrot, his own experimental self-made libc implementation!
Ajouté le 31/08/2018 à 15:03 :
@Nemhardy
No problem! (:
At the moment I'm steadily working on this project to get to an intuitive and easy-to-use solution. If you have any code or just ideas feel free to discuss them here. I really appreciate any support!
Citer : Posté le 31/08/2018 15:07 | #
I refuse to be called an expert è_é
The z case seems to be managed by newlib (reference), at the condition that _WANT_IO_C99_FORMATS is defined. It seems that for this macro to be defined, the --enable-newlib-io-c99-formats must be passed while configuring newlib
Mon blog ⋅ Mes autres projets
Citer : Posté le 31/08/2018 15:14 | #
Oh thank you Cakeisalie5! I did totally not see this. I enabled it for the sh3eb arch by default. I will probably publish it alongside with a some other changes today.
However, I still think that newlib is not C99 compliant (which is no a drama) xD
Citer : Posté le 31/08/2018 17:34 | #
However, I still think that newlib is not C99 compliant (which is no a drama) xD
Really, when you compare the SDK alternative (C89 compiler + partial C89 standard library), with the GCC system (C11 compiler + partially C99-compliant newlib), the improvement is already huge.
So I understand that I don't need to edit the GCC tutorial to add the new flag, right?
Citer : Posté le 31/08/2018 17:57 | #
The improvement is already huge
You are right, of course xD
I don't need to edit the GCC tutorial to add the new flag, right?
No, you don't need to add the new argument, I will add them to the default host configuration
Ajouté le 31/08/2018 à 21:12 :
I just uploaded v1.01 which offers now full support of printf. This includes not only the %z format specifier, but also control characters like \r, \n, \t, \v etc.
The new console behaves just like any terminal, but without scrolling (that's not what most of us need anyway).
Unlike with Print() from fxlib, the cursor's default position is (0/0) (instead of undefined). Yes, indexing is now 0-based :D. To change the position, locate() can be called.
Citer : Posté le 31/08/2018 21:59 | #
Good job!
Are you sure that escape characters are handled by printf() and not the lexical analyzer of the compiler ?
Citer : Posté le 31/08/2018 22:32 | #
Are you sure that escape characters are handled by printf() and not the lexical analyzer of the compiler ?
Of course the \n is converted to the LF character by the compiler. What I meant is that Print does not understand it's meaning per se and prints out some weird special character instead of performing a line feed.
The interpretation of these control characters is the job of the terminal which in this case is fed by _write(). I guess this would usually be the kernel's job. Btw, if you're considering implementing such a feature, feel free to get inspired by my code :P.
Citer : Posté le 31/08/2018 22:54 | # | Fichier joint
Oh, right, just starting this high-level thinking about the standard and I already forgot what kind of platform we're running on. Sorry for that -_-"
Thanks for the reference! I quickly compared with the console I implemented when I experimented around with the early x86 kernel environment, and I see that both of our codes fail to address an efficiency concern: avoid checking all special characters when there is actually none. I attached my own program for reference.
The only way around I see is to define a 256-byte lookup table telling whether there is special behaviour for a given character. This makes it 1 lookup for all written bytes, regardless of the number of special behaviours.
Even though I'm saying all this, it really doesn't matter for the calculator, as we never output really long text. This is more of a theoretic concern about how we can efficiently implement a console. The kernel console is much more sensible to this kind of optimization
Citer : Posté le 31/08/2018 23:11 | #
Oh you're right. To be honest, I thought about that switch, too, but I couldn'd come up with a better way. The lookup table is a great idea. To save space one could even use a lookup table which has a bit only for each character. That would require only 32 byte... or both solutions depending on space/performance optimisation... ideas over ideas xD
I created an issue and postponed the issue since I have a bigger problem right now:
I found a challenge which I didn't find a clean solution for. As previously discussed, I need to replace calloc() by a Casio syscall which in my case is called _calloc_ptr().
calloc() is declared in stdlib.h and defined in newlib/libc/stdlib/mallocr.c:3189. Now the standard procedure to add target-specific code to stdlib is to create a file (machine/stdlib.h) which will be included into stdlib.h by default.
A quick glance into stdlib.h:
#ifndef _STDLIB_H_
#define _STDLIB_H_
#include <machine/ieeefp.h>
#include "_ansi.h"
[...]
#include <machine/stdlib.h>
[...]
What I want to do is something like:
However, I cannot put that preprocessor directive into machine/stdlib.h since it would replace the declaration of calloc with calloc_ptr and result in a redefinition error. I somehow need to #define calloc calloc_ptr after the declaration of calloc. Any ideas on how to do that?
Addendum: If possible, I want to modify target-specific files only (rather than stdlib.h) because otherwise my repository would be a bitch to maintain xD.
Citer : Posté le 31/08/2018 23:16 | #
Couldn't you just put the function declaration inside the define?
Ecrivez vos programmes basic sur PC avec BIDE