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 19/08/2018 19:57 | #
Since many use gint, I also look forward to collaborate with Lephe. I think for now, the libc is conflicting with gint in several aspects. On a later stage, the incomplete libc implementation might even be replaced with newlib.
Citer : Posté le 19/08/2018 20:06 | #
Good news! My current compilers (sh3eb-elf and sh4eb-nofpu-elf) need to be recompiled before I can try out this port, I'll do it asap.
Let's see about the issues you pointed out with gint.
* internals/stdio.h has to be renamed
* the includes of gprint.c and dprint.c have to be changed accordingly
* key_t in keyboard.h has to be renamed
I probably need to strip everything libc-related from gint's sources to avoid conflicts. Out of curiosity, where is key_t used newlib's sources?
newlib/libc/sys/sh/syscalls.c:56: undefined reference to 'end'
In syscalls.c I found
extern char end; /* Defined by the linker */
Tbh, I have no experience whatsoever with linker scripts, maybe you have an idea what to do here.
When using gint I roll my linker scripts so I understand what's going on here. Basically this symbol is calculated and exported by the linker and will typically correspond to the end of some region, maybe code/text/data. It looks like newlib's sbrk() implementation uses it as a region limit for the heap.
Also, by looking at this sbrk(), I can tell that a certain memory layout is assumed, which may not really work on our calculators. Besides, there is no sbrk() in the system, nor any kind of read() or write(). You can tell from the file newlib/libc/sys/sh/sys/syscall.h that a certain kind of syscall procedure is assumed. On Linux, from syscall(2), I know that the syscall instruction is trapa #0x17, here it seems to be trapa #34.
I expect all of this to be configurable and I think we should try to cut off too-low-level code for now. We could, for instance, use a dummy implementation of write() that does nothing and go with sprintf() for a start. We don't have syscalls, we don't have file I/O and we don't have an Unix-like API so we can only get something minimalist.
-
I'm currently in the process of rewriting gint from the ground up for the purpose of porting it to fx-cg50. Your libc may be of use here, as well. All of this is happening on the compat branch of gint's repo, which I invite you to build with although it's not production-ready.
I will create a repo for my gint test/control application, which does nothing special now (a lot of tests that are commented out in a single file) but will expand into a full test add-in when I get the screen drawing back, hopefully in the incoming weeks.
The compat branch is quite minimalist now and has absolutely nothing of a libc except for src/core/memory.c which exports a memcpy() and a memset() functions. Both will eventually be renamed. They are the only dependency from gint to the libc so I plan on keeping the implemented in gint to leverage the dependency (otherwise we'd have a dependency cycle since the libc will certainly depend on gint for timer, date and time, things like this).
Citer : Posté le 19/08/2018 20:31 | #
Out of curiosity, where is key_t is newlib's sources?
I don't really know what it is used for, but it is defined here:
typedef __key_t key_t; /* IPC key */
It looks like newlib's sbrk() implementation uses it as a region limit for the heap
I tried to add a symbol at the end of what I expected to be heap in the linker script. Even if it's the wrong address, the linker error persists.
PROVIDE (end = .);
As I mentioned, until now I did not change a single line of code and mapped sh3eb to the existing sh. The most important code is provided there: the implementation for setjmp. I think the rest of the interface to the underlying platform (the Board Support Package, BSP) which contains the syscalls is not as important. We need functions like memalloc etc. and the rest will be stubs for now.
libc will certainly depend on gint for timer, date and time, things like this
To be honest I would like to avoid having libc depend on gint (or any library infact). I'd prefer moving the code over to the libc (I'd give you the credit ofc) and have gint depend on libc which feels much more natural to me. Frankly, I do not anyone expect to use libc without gint, but it just seems cleaner to me that way... What do you think?
However, it's a long way before we need to discuss this
PS.: How do I write inline code o.O?
@Breizh_craft works like a charm, thanks!
Citer : Posté le 19/08/2018 20:35 | #
You can use backticks (`) or [inlinecode]code[/inlinecode] to write inline code ^^.
Citer : Posté le 19/08/2018 20:54 | #
I tried to add a symbol at the end of what I expected to be heap in the linker script. Even if it's the wrong address, the linker error persists.
PROVIDE (end = .);
You almost got it right. On SuperH all C names correspond to symbols with a leading underscore. Certainly PROVIDE (_end = .); would be better.
I have not yet looked at the documentation for now, but the page you linked will definitely be useful!
This is a difficult question indeed. So far I see gint as a kernel, which is why I suggested that the libc depends on gint. But it would prevent the library from being used anywhere else... which we'd like to avoid, if possible!
We could let gint depend on the libc, but "there's no need" since gint does really not use the libc functions at all. I've ported around half of it and it still needs just memcpy(), the rest of the core memory functions being required by gcc to build in the first place.
Yes, and we can always add a configure switch to build versions that actually depend on each other.
Something else I probably ought to mention is that gint provides its linker script and C runtime. This may, again, clash with the standard library. A possible solution would be to edit gint's linker script to allow linking with newlib if newlib require any linking facility, and requiring that the user of your libc provides its own C runtime, leaving the choice to use gint or a more traditional, fxlib-based environment with a crt0.s that we've been using for ages.
Citer : Posté le 19/08/2018 22:25 | #
Certainly PROVIDE (_end = .); would be better.
You're absolutely right, should have known that xD.
So far I see gint as a kernel, which is why I suggested that the libc depends on gint. But it would prevent the library from being used anywhere else... which we'd like to avoid, if possible!
That makes perfectly sense to me. From that perspective newlib should indeed depend on gint. The configure switch is what I would have suggested as well, good call!
Something else I probably ought to mention is that gint provides its linker script and C runtime
I don't know what you mean by C runtime, but later on, libc should not require a specific linker script (I think it's only used by _sbrk anyway). I intend to have newlib compatible for both fxlib (basic feature set) and gint (enhanced feature set).
Citer : Posté le 19/08/2018 22:34 | #
Basically the C runtime is the small program that loads the add-in into memory. In embedded systems such as our calculators, a typical task for it is to initialize the RAM sections by copying the contents from the add-in file which is mapped in ROM.
When running fxlib under the SDK the INIT_ADDIN_APPLICATION() function is assigned to that task. You can see that the default places it in the pretext section which is a very strong hint.
When using fxlib with GCC, it is common to use a small assembler script called crt0.s (stands for C runtime), for which the source is on the path of being lost. I think Kristaba's behind this. (Kristaba is a formerly-active member of the community who worked on a POSIX-compliant kernel going with the name of FiXOS. He and the people helping him could not finish the kernel but they did a lot of interesting stuff.)
When using gint, the C runtime resembles a kernel's initialization phase. The program is loaded to memory, then gint does a bit of hardware detection and starts initializing its drivers.
Cakeisalie5 would argue that in a modern, well-written system the C runtime would be provided by the libc. Honestly I don't know how we could pull this out and I suggest that we leave the C runtime to the library user
Citer : Posté le 19/08/2018 22:57 | #
Oh thanks for the insight! Newlib indeed contains newlib/libc/sys/sh/crt0.S which I did not have a look into yet. I guess we could replace that with our own implementation. I have to think about all this... (*-* )
About your compat branch: I could build it, but I have to have a deeper look into it another day.
Citer : Posté le 19/08/2018 23:15 | #
About FiXOS, I remember that Kristaba has made his own libc. Sources can be found here. I don't know if it's relevant, but it can help. FiXOS sources are on the same GitLab instance.
Citer : Posté le 19/08/2018 23:23 | #
Looking at lines 66..119 which correspond to SH4 and lower, this is pretty much the same thing as our usual assembly file.
Looks like newlib loads its own stack pointer (symbol _stack). Normally this is not necessary for us as the system that launches the add-in sets one for us.
Since we don't have an FPU, the rest of the script just clears the BSS section, calls main and exits, which every of our C runtimes do. I think we can safely use our own initialization instead of this one.
Also note that the _end symbol is referenced here as the end of the BSS section. Symbol _stack is probably from the linker script as well.
There doesn't seem to be any linker script in the newlib directory, but there clearly are in libgloss, which -I didn't expect it- turns out to be part of newlib as well:
The libgloss directory contains code specific to particular platforms on which the library will be used, generally referred to as the Board Support Package (BSP). Any particular target architecture may have multiple BSPs, for example for different hardware platforms, for a simulator etc.
libgloss/sh contains in fact just linker scripts - 4 of them. Looking at what they contain, I think gint's linker scripts can usually provide all the functionality; the usual gcc + fxlib environment can as well. With a bit of tweaking I expect this part to actually work.
So, to sum it up, I suggest that:
- We drop most of their crt0.S and include the little remaining functionality in our init scripts
- Same for the linker scripts (mainly some section names to add in the right places)
Gonna blow up everything
Citer : Posté le 20/08/2018 18:20 | #
Wow this is getting fun xD
So, to sum it up, I suggest that:
- We drop most of their crt0.S and include the little remaining functionality in our init scripts
- Same for the linker scripts (mainly some section names to add in the right places)
To be honest I try to keep the changes to the library at a necessary minimum. I'll be glad later on when I need to maintain the library and rebase the upstream project from time to time to keep it up-to-date. That means that I try to use the existing crt0.S and linker script and change (delete) the parts that need to be changed (deleted) (at least that's my plan).
As for the gint support: I think it would be best to get the std lib up and running first (basic feature set) and then we will see what will depend on what and how
Citer : Posté le 20/08/2018 18:43 | #
I was wondering about that. If you plan to maintain it seriously then you're right, we need to change a minimum of code!
For the C runtime and linker scripts, we actually don't need to change the sources. I understand that we have settled on leaving the C runtime out of the libc, is it right? In this case we need only alter the existing runtimes (fxlib/gcc or gint or whatever!) to support the "features" required by newlib. Basically this is specially-provided symbols or specific section names. Then we "ignore" newlib's runtime; we just don't compile or link with it.
As for the gint support: I think it would be best to get the std lib up and running first (basic feature set) and then we will see what will depend on what and how
You're right, but you will need a runtime to test out the basic feature set of the library in an add-in! I strongly suggest starting with fxlib/gcc because it's stable and easy to roll with.
Citer : Posté le 20/08/2018 19:33 | #
Unrelated question: is there a simulator for the fx9860GII like the one shipped with the Casio SDK available for linux? If not, do you know any other way to debug my programs?
Citer : Posté le 20/08/2018 19:35 | #
Yes :
- There is a free emulator, however it is on OS 1.00: https://www.planet-casio.com/Fr/logiciels/voir_un_logiciel_casio.php?showid=19
- Casio provides the Manager PLUS emulator, with a trial period of 90 days. Drak has done a tutorial on how to set up a VM to have infinite trial period: https://www.planet-casio.com/Fr/forums/topic15178-1-%C3%89mulez-gratuitement-une-Casio-Graph-75+-sur-votre-ordinateur.html
Ecrivez vos programmes basic sur PC avec BIDE
Citer : Posté le 20/08/2018 19:56 | #
Thanks Zezombye! I fear that the first tool is for "Graph 75, 85, 95 seulement" and second one is for Windows in a VM which is a very suboptimal solution for me since I develop on Linux. Additionally I don't know if "Casio Graph 75+" covers my Casio fx9860GII. To be honest, I doubt so.
Citer : Posté le 20/08/2018 20:03 | #
fx-9860GII is just the international name of the Graph 35 (or graph 75, I don't remember). Either way it's a monochrome calc, so it should be compatible with the emulators.
If you develop on linux, then all the emulators are on windows either way. I think you could run them on wine though, the VM is just to bypass the trial period.
Ecrivez vos programmes basic sur PC avec BIDE
Citer : Posté le 20/08/2018 20:21 | #
Oh I didn't know that, thank you!
all the emulators are on windows either way
What a pity!
Ajouté le 20/08/2018 à 20:24 :
I ran first tests (commit 4a6c165f):
Using the fxlib.h I get a nasty linker errors (section overlap) which I don't know how to resolve.
Using gint I can get malloc, strcpy and free to work. I did use Lephé's (modified) linker script.
For both tests I used the linker scripts and/or crt0.s files of gint/fxlib.
Citer : Posté le 20/08/2018 20:26 | #
You're right. Kristaba also started a long time ago a port of QEmu for the fx9860 Series, but it was stopped before the first visible results has been produced…
Here is the code…
Citer : Posté le 20/08/2018 20:26 | #
What errors exactly are you having?
Ecrivez vos programmes basic sur PC avec BIDE
Citer : Posté le 20/08/2018 20:32 | #
sh3eb-elf-gcc -o build/cryptfx.elf build/cryptfx.cpp.o -m3 -mb -ffreestanding -Iinclude -O2 -std=c11 -T ld/cryptfx.ld -Llib -lc-lgcc -lfx
.../ld: section .eh_frame LMA [0000000000301dd4,0000000000301e27] overlaps section .data LMA [0000000000301dd4,000000000030260f]
.../ld: warning: section`.bss' type changed to PROGBITS