isotherm / betawise

Tools to create applets for the AlphaSmart NEO / NEO2.
MIT License
39 stars 4 forks source link

Build custom toolchain for Alphasmart devices #4

Open isotherm opened 3 years ago

isotherm commented 3 years ago

The current workflow requires all global variables to be declared within a single specialized struct, that special compilation options are used, and a special linker script assembles the pieces and adds the header. This makes porting difficult for a lot of larger and/or open source projects.

A proper development platform would provide its own toolchain. This toolchain would likely need minor patches for gcc to accommodate the global data and ld to produce applet binaries. Similar patches were made for PalmOS; in fact, given the history with the Dana, the Neo's toolchain may have just been a patched or customized PalmOS toolchain.

A port of a standard library, like uclibc, might also be useful, but it would be a separate effort.

lykahb commented 3 years ago

GCC and binutils have a GPL license. That requires Renaissance Learning to share their patched toolchain. However, I doubt that they have ever shared it and that it wasn't lost by now. It may still be worth asking.

neimanpinchas commented 3 years ago

They might have used assambler and not C at all, back in these days

isotherm commented 3 years ago

The request for source code would have to come from someone to whom they had redistributed the toolchain. Unless someone has this in their personal possession, we likely don't have a GPL claim.

I've seen some other commercial compilers that were used for Palm OS back in the day, and those vendors offered customizations. It's possible that it's not GCC-based at all. Nevertheless, it should be possible to produce a GCC toolchain (even a modern one) for this, even a modern one. Basically we need to: 1) get the global register pointer working and 2) create a custom Alphasmart applet binary format.

Although it would certainly be possible to write this in assembly, most M68K work of this era was done with C compilers, and I see evidence in the ROM that it was C compiled. (In particular, Ghidra decompilation can produce coherent C code, including switch/case logic that would've been too opaque for an assembly programmer to produce.)

isotherm commented 3 years ago

The real thing we need to decide here is what level of support we want to bring to the Neo. Gcc actually already has support for position-independent code (PIC) on this platform, and it uses the proper A5 register. However, it is expecting us to have a full ELF loader and be doing relocations and loading shared libraries.

If we are shooting for basic I/O (e.g. print character, get character) like EhBASIC or Micropython need, that is one thing. If people will want to write or compile programs using various shared libraries (curses, etc.) then that would be quite another. At that point, a ucLinux or other OS (EmuTOS?) port should be seriously considered, though it is hard to see how disk-based operating systems could thrive with only 512kB to share between RAM and storage. (Maybe some sort of flash filesystem could be considered, but I still haven't checked what flash chip is used and how many write cycles it supports.)

lykahb commented 3 years ago

In theory, porting a new OS is cool but, as you said, the space to run applications would be a constraint. Compiling more complex programs that have shared libraries would make it easier to tinker with Neo. But it's not clear if anyone is interested in this. I use Neo mostly as a writing or a note-taking tool and am only interested in getting a scripting language for quick calculations.

isotherm commented 3 years ago

@lykahb Out of curiosity, what calculations are you wanting to do beyond the Calculator applet or EhBASIC (it has floating point)? Maybe there would be something like bc that could work. I also thought of a TI-92 emulator, as those had M68K processors... But that is more work. :-)

lykahb commented 3 years ago

Both calculator and ehbasic feel quite limited . Also, ehbasic requiring keywords to be upper-case is annoying. The bc or TI-92 emulator may have better user experience. I do not know them well enough to tell.

I like entering the data first, and then processing it. It is convenient to use list comprehensions or map/fold. For example, entering a list of measurements and computing mean and variance. Basic probably can handle this, but it's easier to break the workflow and open a scientific calculator on a smartphone.

Other than basic IO it would be nice to have persistence and save the current work in a file. Also, if the applets are not fully isolated, we could edit a script with alphaword and then open it with an interpreter.

isotherm commented 3 years ago

I did some basic research, and it seems very likely that they used a Sierra 68000 C Compiler for this, as many other 68K products were doing at that time. It has the appropriate options to allow an A5-based data segment. However, I tried using the compiler and it is very outdated and doesn't accept modern C code. Optimization also appears poor and there are reports of bugs. I don't think that it is a way forward.

Effort now will focus on the minimal possible patch to binutils and/or gcc to produce the files we need. There doesn't seem to be nearly enough interest in this to justify a full port, but a simple patch should be workable.

isotherm commented 2 years ago

The current repo now has a modified toolchain, but I still can't compile Micropython due to the size of the code and the need for relative jumps.

One option was to write the necessary code to make gcc's GOT (global offset table) just work, however this table can consume a fair amount of RAM on a device like this. The other option is to generate 32-bit offsets for jumps and then make the linker to do link-time relaxing/optimizing to 16-bit offsets where possible. This is more involved but probably the right answer for this platform.

When I get the chance, I want to try generating 32-bit offsets and get a Micropython applet built. Maybe we could be happy enough for now just telling the compiler whether we want 16- or 32-bit offsets for a particular program. ROM is at much less of a premium than RAM on these units... especially if we are going to start running interpreted code.

isotherm commented 1 year ago

The changes in 9df5d0 added 32-bit offset calculation. However, compiled programs are still not properly initializing RAM. In particular, data in .data.rel.ro (and similar) needs to be initialized at run-time, due to possibly containing pointers to code and/or RAM, but no initialization is being done.

This would require some C startup code and including the relocation tables into the applet, or else auto-generating some sort of initialization routine from the relocations.