µCLinux on Pluto 6

Last updated: 23 Feb 2013
Share this:
 

While doing my industrial placement year during university, I was looking around for an interesting project for the big "Final year project", a rather more practical version of a dissertation. One of the lecturers wisely advised us all to call it the final seven months project, because if you left it until you got back for your final year after the placement, seven months was all you had.

Whilst doing said industrial placement at Heber, a company which designs and manufactures electronic controls, I was working on various new device drivers and software maintenance for the Pluto 6 gaming control board (By gaming, think fruit machines/amusements with prizes, not Virtua fighter III), one of the company's top sellers.

A Pluto 6 gaming control board.

The main CPU on the Pluto 6 is a Freescale Coldfire 5206e microcontroller. The Coldfire line has its ancestry in the Motorola 68000 series, with, as is typical for such SoCs, some CPU instructions taken out, new ones put in, and the evolution from CPU to MCU with the addition of a smattering of integrated on chip peripherals. The 52xx Coldfire variants are 32bit chips, but with no memory management.

Around this time I discovered uCLinux, a branch of Linux for systems with no memory management unit. One of the systems with good uCLinux support at that time happened to be the Coldfire series, including the 5206e used on the Pluto 6.

The obvious answer therefore was to port uCLinux to the Pluto 6 board. Since the board was designed to go into arcade cabinets, it is chock full of IO, banks of multiplexed outputs, numerous serial ports, an FPGA with various facilities, not to mention a Fujitsu Cremson (Yes, Cremson, not Crimson) MB86290A graphics controller on a seperate plug in card. Running Linux on the board would surely present all sorts of exciting opportunities! So having convinced the powers that be of the merits of such an idea (With a lot of help from my boss at the time Marc) off I went back to Uni with a full Pluto 6 dev kit.

What follows is a brief overview of some highlights of the project. A more technically detailed account of the events are given in the final year project report which was the formal produce of all this practical hard work. I think the report may provide some useful background and pointers if you're trying a port yourself for the first time, along with everything you can find by following the links on the uCLinux website.

Setting up a development environment

The Coldfire line uses Background Debug Mode, which offers similar abilities to JTAG. If you're ever working with Coldfires and don't want to buy an expensive debugger, I'd recommend the BDM Tools package. I had a cheapish parallel port BDM dongle made by P&E micro, which came with the Pluto 6 dev kit. At the time that I was setting up for this project, the BDM tools came with patches for GDB, I used those to patch GDB 6.0, then wrote a .gdbinit script to reset and configure the board. I see that since then BDM Tools now provides a BDM gdbserver, so a regular build of GDB can be used with remote protocol instead.

For a toolchain I went with the binaries available on this page.

Getting the kernel to boot

What followed for the next few months was a lot of sessions flapping between the pages of Understanding the Linux Kernel and Linux Device Drivers, followed by furious grepping sessions and the occasional "Ahaaah!" of realisation as I made my first forray into kernel porting. The kernel would break at various points in the boot as I had different things set up incorrectly.

After settling on the base addresses for the DRAM, peripherals and other chip selects, the biggest breakthrough came when I finally grokked the fundamental difference between the address space of a process in a system with an MMU and one without, and the significance of the PAGE_OFFSET value in defining that layout. On "Grown up" Linux, PAGE_OFFSET points at the address of the kernel memory (Where the kernel code is loaded to and executed from when a process enters kernel mode) in the standard virtual address space layout used by every process in the system. On uCLinux PAGE_OFFSET simply points to the physical base address of the usable memory on the system. Once I got PAGE_OFFSET right for my intended base address, and a few other issues fixed, the system finally booted all the way to a sash prompt! I ran ls, it worked! I ran ls again, it crashed.

Now, the board only has 1.8MB of DRAM (Well it was only designed to run bare board code developed in-house), at one point I thought it may be a bit ambitious trying to run the kernel in that, alongside a RAMFS rootfs, then try to run some binaries in whatever RAM was leftover. That said, I did indeed by that point have a heavily stripped down kernel (All networking ability configured out for example), and a barebones rootfs with a few device nodes, init and sash loaded into ~1.8 Megabytes of RAM and booted to a prompt. Sash is like busybox but smaller, with a choice selection of coreutils imitations included in it. When commands are run in sash, I presume it uses malloc. After two directory listings or so, uCLinux's power of two allocator had evidently fragmented the limited number of larger contiguous physical address regions available into too small a size to fulfill the required allocation requests and run anything else in.

More RAM would be needed to make anything more than a shell prompt happen on this system. Initially I tried using the video memory for the Fujitsu MB86290A, which would have given me 16MB of RAM to play with.

Output on display of a kernel loaded into video RAM on the MB86290A
The Heber Video demo halted by GDB and a uCLinux kernel code downloaded to the VRAM used by the Fujitsu graphics chip; the black section in the middle of all that code is the empty bss region. The Heber logo is on a different display layer, hence why it isn't overwritten in video memory by the kernel.

On the first few attempts to run some code from the video RAM the program counter wouldn't increment correctly, made evident by watching the PC whilst stepping the first few instrucitons in GDB. I suspected the instruction cache was misconfigured, however a path of lesser resistance presented itself. I'd heard something before I finished my placement about a RAM card which could go in one of the graphics card slots, so I popped back into the office. And so there on a dusty shelf I found an apparently one-of-a-kind 8MB DRAM card.

An FPGA on the RAM card handled all the DRAM timings, so it just sat on chip select 0 and behaved more like a static RAM. It was battery backed as well. Just load a binary+rootfs to 0x0 through GDB, and at reset it'll boot ever after, even when power cycling. Perfect!

Device drivers

Framebuffer

I set about writing a frame buffer driver for the Fujitsu Cremson, which involved a lot of incorrectly coloured stuff on the screen at various points in the process.

Incorrectly coloured green on pink framebuffer console output on a Fujitsu Cremson MB86290A Incorrectly coloured and strided green on blue framebuffer console output on top half of screen only
Incorrectly coloured and strided green  on black framebuffer console output, odd and even rows shown side by side on top half of screen only Incorrectly coloured blue on grey framebuffer console output
Incorrectly coloured and noisy blueish  framebuffer console output Incorrectly coloured orange on black framebuffer console output
Correctly coloured uCLinux framebuffer console output NanoX output running on the uCLinux framebuffer
Top 4: Toxic penguins!
Bottom left: Finally a correctly working framebuffer console. Bottom right: Nano-X with Nano Tetris.

Multiplexed LEDs

Next up was a driver to enable the LEDs driven by a multiplexer in the FPGA. The command:

# echo 0123456776543210 > /dev/lamps10
# echo 0707070707070707 > /dev/lamps15

Would produce:

A really blurry photo of some multiplexed LED outputs.

Vaccuum flourescent display

# echo hello\ world! > /dev/vfd0
Hello world displayed on a 7 segment vaccuum flourescent display

CompactFlash

There is also a CPLD on the board which, among other duties, presents the registers from an inserted CompactFlash card or ATA drive on the data bus through the CPLD chip select. The uCLinux patch provides a nice canned ATA driver, which took some fiddling however to get working due to the ATA interrupt from the CPLD being shared with the graphics chip VSYNC, and the need to constantly alter the databus width in the CPLD chip select to satisfy the expected results of IN and OUTB/W/L from the rest of the IDE subsystem. Once this was working I could finally switch from the romfs to a rootfs on a CompactFlash card.

Project presentation

Everyone on the degree course took turns giving a presentation on their project to each other, here are the slides from mine:

UKUUG 2006

My project tutor Craig suggested we do a paper on the project and present it at the UK Unix and Open Systems User Group conference that year. So he massaged the report into a conference paper, and I sorted out a presentation, which I then gave in a dark lecture theatre on a sunny day in Brighton. The slides from that talk are here:

I think some of the audience may have been disappointed that I didn't know any cheats for gambling machines. I've long since switched to just saying "Yes" and nodding knowingly. I do not, in fact, know any cheats for gambling machines.

 
comments powered by Disqus