Since the last post I have added functionality necessary to make it possible to use the computer from a directly connected keyboard and screen.
This required two things:
- Making the already written PS/2 controller VHDL implementation available to the Linux kernel by adding a PS/2 driver.
- Modifying the existing, and somewhat hacky, VGA controller for my video card and writing a wrapper to Linux’s framebuffer infrastructure to make use if it.
Both tasks turned out to be fairly straightforward.
Linux has an infrastructure for supporting PS/2 devices attached to ports presented via platform-specific hardware. The driver I’ve created shunts bytes, read by the hardware at the serio subsystem, which then interprets these bytes, eventually generating keyboard and mouse events. It likewise is used to forward on bytes to the PS/2 devices to do things like manipulate the LEDs found on keyboards. In terms of getting the keyboard working, this went fairly easily.
The framebuffer driver was remarkably easy to get going, but before looking at the Linux side I first I had to modify my exiting VHDL to implement the required screen mode: in this case 640×480 at 60Hz, but in 256 colours. One interesting angle to this is the palette: it was held in dual ported memory, with one side read by the video generator, and the other side read and written by the processor, so it could change the palette, the default palette being the standard 256 colour VGA one. This was a little involved, and even once “finished” it wasn’t perfect: I had to introduce wait states in the MAXI030 FPGA since the wait signal generated by the card didn’t appear to be generated properly, despite my best efforts. In any case, eventually I had some decent images:
This image, which started out as a JPG, was scaled and colour reduced into a BMP file, which was transferred across the ethernet link, described in the previous post.
The MAXI030 framebuffer driver is very simple, and simply configures where in the memory space the buffer is, along with its resolution and colour depth.
Getting Linux to make use of the framebuffer and PS/2 was done next, using the drivers previously added to the kernel:
I was very pleased to get to this point, though if you look closely at the bottom of Tux you will spot a line of red pixels which should not be there. This indicates a subtle timing issue with the 68030 asserting a colour onto the video card palette memory. I had a further issue at this point: the Linux kernel exposed a problem with the PS/2 controller I hadn’t up to that point seen. This was undoubtedly caused by not having a simulation harness for the controller.
This driver is a little similar to the PS/2 driver just described: it operates as a go-between between the platform specific hardware, in this case the I2C controller implemented in the MAXI030 FPGA, to the I2C infrastructure in the Linux kernel. Linux terms these drivers “busses”.
The really interesting thing is that once a bus has been created, peripherals can be easily attached to those busses. For MAXI030 I have attached two:
- The aforementioned DS1307.
- The LM75A (PDF) temperature sensor
The stock driver source for these two parts were used; no MAXI030-specific changes were needed. Peripheral ICs can either be added in code, which is what I’ve done via the config.c module, or it can be done at runtime.
Because the Debian userland I’m running is somewhat old, and designed to run on older kernels, some hacks were necessary to make this work with the up-to-date kernel I’m running. For instance the hwclock program requires a /dev/rtc symlink to /dev/rtc0, since on new kernels multiple RTCs can be present, whereas the hwclock program expects only one, at /dev/rtc.
As well as having a working RTC, it was pretty nice seeing the temperature sensor working inside Linux.
At this point I have not discussed any negatives. Unfortunately there was one quite large one: the text console was pretty slow, especially with scrolling. Certainly not unusable, but not great either. This could be improved with two changes:
- Reducing the colours presented to, say, 16.
- Adding hardware acceleration to the VHDL implementation, and then leveraging this in the framebuffer driver.
The latter is probably the most interesting. Without any acceleration, all pixel drawing must be accomplished with processor code. This is obviously quite expensive, especially if one considers something like scrolling the screen. The framebuffer implementation in Linux supports acceleration for key drawing functions, such as copying one area of the screen to another. By exploiting these hooks and calling into the hardware via registers to satisfy them, it should be possibly to greatly speed up drawing, especially scrolling text in the console. This could be achieved in a similar way to how I previously implemented hardware accelerated drawing for my video card.
At the present time I’ve not implemented either of these ideas, for a simple reason: neither can be utilised by the X server framebuffer driver.
After playing about with the framebuffer console, the logical next step was to see if it was possible to run the X server on MAXI030 using it. This would end up being a major milestone for the project: a working, if rather slow, GUI.
I was pleased to see someone had written an X server display driver module for the framebuffer, called fbdev. Even with the limitations mentioned (it supports only 8, 15, 16 and 24 bit colour and does not support any acceleration) I thought it would be great to see X running on MAXI030:
Unfortunately this nice picture hides a secret: the X server was very slow to use. Just starting it took perhaps 3 minutes. And dragging windows around is fairly painful. But I was still pleased.
Yet another problem then appeared: the PS/2 implementation detected the mouse I’d attached via a Y-splitter, but mouse movements were erratic, with the kernel reporting a loss of sync in the PS/2 byte stream. This was particularly likely to happen under disk load. I later noticed the same problem, only very occasionally, with the keyboard. Since the PS/2 interrupts were the highest priority used, it appeared that the only reasonable explanation was that something, probably in the IDE driver, was disabling interrupts and causing PS/2 bytes to be lost.
The solution to this was to introduce a FIFO in the PS/2 controller implementation. This FIFO would queue up bytes so a byte could be received on the port before the previous byte was read back by the processor, without that previous byte being discarded.
This was actually surprisingly easy to do. Using the Quartus MegaWizard an 8 byte deep FIFO was created. The read end was attached to the external databus of the FPGA using the existing hardware address, and the write end was attached to the PS/2 controller’s data output. In addition, I extended the PS/2 status registers to supply the number of bytes currently waiting to be read in the FIFO, since I had a few bits free in the 8 bit status register.
After playing around with this new functionality inside my machine-code monitor, I straight away noticed some weird problems with erratic behaviour. Sometimes MAXI030 would even refuse to reset cleanly. The problems looked precisely like those I saw with MIDI020 previously. Making changes to the VHDL coding in trivial parts of the design, such as wether the user controlled LED was linked to its controlling register, would result in a non functional board.
As a fairly desperate means to have a functioning board again, I have switched the clock oscillator back to a 20MHz part and this has resulted in a useable board, including working PS/2 FIFOs, albeit a board that now runs at half the speed.
I have explored various approaches to getting the board working at its maximum speed. All, so far, without success. I thought I was onto a promising approach when I, at last, figured out how to replace the sequential address decoder with a combinational one. This did not result in any improvement. I am determined to come back here, as this board has many more projects to offer. But for now, I think, I must move on to something else.
And that something else is a new softcore processor…