Keeping Contiki 1.x alive

Posted by pulkomandy on Sun May 7 20:30:24 2023  •  Comments (1)  • 

Contiki is a small operating system originally developed by Adam Dunkels. Version 1.x became famous on the internets after he ported it to the Commodore 64. The system came with a small GUI and ran reasonably well. It is written in C and uses a few nice tricks to run efficiently on low memory systems.

Contiki became "big and professional", well, mostly profesionnal, and in version 2.x, the GUI was mostly removed and the fun 8 and 16 bit machine ports all abandoned. Now it is useful for actual projects, running on small sensor boards and the like.

The best place to find info about the old Contiki version is the Hitmen demogroup page. I was a bit annoyed about the Amstrad CPC port description there: "runs slowly, does not look nice, and could probably be improved. But still worth a look". Certainly the CPC deserves better. And so I started hacking. That was in 2014.

The CPC port was initially developped by Kevin Thacker, who got it running, and kind of stopped there. It was indeed very slow, but the main cause was the implementation of the "clear rectangle" function as a loop putting space characters all over the display. But I went on and changed quite a few things to get it to look better, be faster, and saved several kilobytes of RAM (partially thanks to improvements in SDCC, and partially through rewriting more of the UI code with small assembler parts, adding missing "const" in various places, etc).

I also simplified the build quite a bit, in particular I had to rework the generation of symbol definition files that are used to link the loadable PRG files to the Contiki kernel. On the CPC port, these files are generated from the SDCC generated mapping files, now using some SED scripts to convert them to the appropriate format. I also made several adjustments to use newer SDCC versions over the years.

Later on, I also ported Contiki to the Bitbox console as well as the VTech V.Smile. The V.Smile port is still unfinished and waiting for the development of a proper toolchain for its unusual CPU, more on that later in another article.

Anyway, this brings us to today where I finally decided to update the port to use the latest version of SDCC. The SDCC compiler changed their calling convention in version 4.2 and finally added a way to pass parameters to functions using CPU registers. Before that, they were pushing parameters to the stack, and making that more complicated by insisting on pusing only 1 byte, when there are no instructions on the z80 to do so (PUSH and POP always work on 16 bit register pairs).

This, of course, requires all functions written in assemby to be updated. But before I got to that, I had to fix a patch to SDCC. One specificity of Contiki is its ability to load programs at arbitrary addresses in RAM to execute them. On a modern machine, this would be handled either by using the MMU to provide a fixed memory layout to the program, or by compiling the code as "position independent". But none of these are available on the Z80 CPU (well, you could, with a lot of custom hardware, but not on an Amstrad CPC at least). So, Contiki has to "relocate" executable, that means, after loading them into RAM, patch every address referenced in the code to adjust it for where the program was loaded. Fortunately there is some support for this in SDCC and Kevin provided a patch to generate a relocation table that lists the places that need to be patched in the final binary of each program.

I have kept this patch up to date with the current version of SDCC over the years, and version 4.2 needed a new change. It internally represents addresses as 24 bit instead of 16, I guess to allow support for banking. This resulted in corruption in the generated .hex files, and a bit of confusion until I managed to convince SDCC buildsystem to generate binaries with debug info for the linker, so I could look at what it was doing. It took a bit more guessing due to Haiku debugger not showing the value for global variables yet, but eventually I figured it out.

The next step was fixing a segmentation fault in the compiler. Fortunately, I could locate an existing bugreport with a fix, and apply the changes to my version of SDCC to avoid the problem.

And finally I could get to the part where I have to adjust all the assembler code to the new convention. Several of the functions could be simplified or even removed completely (when the calling convention matches that of the CPC firmware, it's possible to call directly into the firmware).

Converting the functions was not too hard, despite me making some stupid mistakes (don't pop something into a register if you need the value that's already in that register...) and having to fix another place where a function corrupted the IX register while SDCC didn't expect that (since it's the frame pointer, it assumes all functions preserve it, including ones written manually in assembler).

In the end, Contiki is now running fine with SDCC 4.2! I then tried to turn the optimization level (max-allocs-per-node) way up to 20 million and let things compile for a very long time. But this failed, the compiler generates instructions that the assembler doesn't accept because they are undocumented opcodes (that exist in the z80 implementation, but were not mentionned in the official documentation and removed from later CPUs like the z180).

So for now I have turned that back down, and I will test again in SDCC 4.3 where support for undocumented opcodes will be official and toggleable with a command line switch.

In the end, this new version of SDCC allowed to raise the free space in RAM with Contiki running from 24 to 26K, which is not bad at all! And there would be ways to free even more, by moving the Contiki Kernel to a ROM or using the RAM banks of the CPC to not have the code and the framebuffer share the same 64K space.

... so a few days later I did just this. It took some bug hunting and some not so clean tricks to get the file generated the way I wanted, but Contiki is now a ROM. Which means the free space is now 37K out of a 41K "heap", when the desktop and the "memstat" apps are both running. This is possible because the ROM uses the same memory space as the framebuffer, and so, suddenly there is 16K more of address space to use.

I think I could also implement a proper GUI driver that is not restricted to simulating a GUI from textmode. It could be made to look quite a bit nicer with a smaller font, and not being restricted to 8x8 pixels character blocks with only 2 colors for everything, and also make it use an overscan display instead of just 320x200. That would require moving the apps to memory bank so most of the main memory can be used for the display. But I already planned that when I started working on Contiki 10 years ago, and I have not started it since. And I think it's time to move on to other projects.

I still had two bugs to fix: during startup, there were some things written to the framebuffer that shouln't be there, meaning the linker somehow put non-const data in the ROM. And, the icons on the desktop are not loading. These two were related, it tuns out I had added a "const" to the icons to workaround a problem with the generation of the DSC files (these are files with just the icon data, used to quickly show the icon directory in Contiki). And so they were in the ROM, but adding an icon to the desktop actually writes some things in the icon data structure... So I made my hack a bit more complicated and now it's working fine.

While investigating this, I also found that the borders for some windows did not stop drawing where they should, and continued all the way to the bottom of the screen. I'm not sure if it was a compiler bug or a mistake in the code, but I have rewritten the code in a slightly different way and it's working fine now.

So, it is time for a new release of Contiki after 5 years of doing nothing, and two weekends of hacking!

Download Contiki 1.4 for Amstrad CPC. You will need to flash the ROM to any ROM slot, and put the DSK in your disk drive. Then type

to start the OS. Enjoy!

Get the sourcecode using Git if you'd like to help with this project or have your own fun experiments with it. I don't know when I will look again into it!

I have also submitted the patches for Haiku support to the SDCC team, and we are discussing which of the changes are useful to merge on their side. Kevin's relocation patch has a known bug, that will need to be fixed before they accept it upstream. Unfortunately, fixing it requires some changes to the way the relocation info is encoded. I'll see what I can do about it.

I also found bugs in the ACE CPC emulator (setting the PC register from the Z80 editor window actually sets IX instead?). So that's another bug fixed in ACE and I should look into that as one of my next projects. I want to do a point release of it with a collection of bugfixes, and port and publish all the ACEpansions that are available for the MorphOS version now. Oh well, the TODO list never really goes down!

gravatar Comment

Posted by Paul, Russia on Mon May 1 23:48:33 2023

Good job, boy, go on!

Leave a comment

Name: Mail: