The IO boards arrived about a week after putting the order in. The front of one of the boards:
And the back:
Interestingly I received two extra boards. An extra usable board and another one. The other board had been used for some kind of testing by the manufacturer as it had a piece cut out of it. The box also had a test sheet in it. It would be interesting to understand what all the tests were!
For the first time ever, I’d previously gathered up all the parts needed to complete the build so everything was ready to start soldering when the board turned up.
I noticed one little problem right away: the RJ10 connector for the keyboard lead didn’t fit. The four metal pins were fine but the two plastic mounting pins didn’t. KiCAD contains a footprint for a 6-way RJ11 socket but not a 4-way RJ10 so I made my own based on the RJ11 footprint. Unfortunately the socket is slightly narrower. Luckily the problem was easily fixed with a 5mm drill bit and the drill press. Next time I will find a datasheet to check the dimensions instead of just assuming.
The first job was to solder up the two 40 pin sockets that join the IO board to the MINI000 board. This was complicates by the use of “long tail” sockets, instead of ordinary, albeit upside down, ones. You can’t seem to get 40 pin long tail ones. Instead I had to hand some 1 by 10 pin sockets; the plan was to use four in each half of the, in total, 80 pin connector. This involved some sanding of the ends of the plastic as the sockets are not designed to be butted up against each other. The end result is not perfect but good enough. I would have liked to have used ordinary sockets but the long leads have already proven useful for being able to attach the logic analyzer to the board.
Here is a picture of the board just prior to soldering up the long tail sockets:
Kepton tape was used to hold the sockets in position.
After soldering up the sockets I was pleased that the MINI000 attached nicely, but it was obvious that the MINI000 JTAG connector was going to be be obstructed by the SVGA connector, and this was going to be an annoyance.
While attached I briefly powered on the MINI000 board and measured for Vcc at a few key points.
Next up was to solder up the power LED and resistor, and the FPGA parts: the FPGA, configuration flash, and JTAG header. Surprisingly, and I shouldn’t really be surprised, the JTAG chain looked good. Here’s a, somewhat fuzzy, picture of the board in this state:
I’d previously, before the board arrived, modified the VHDL for the VGA controller and updated the pinning for the FPGA. This mostly involved factoring in the 3 bits of red, green and blue and the two additional 12nS SRAM ICs. To test the resistor DAC I made the background for the text display into a checker-board pattern of differing shades, by XORing the horizontal and vertical counters, with red, green and blue coming from different slices of two bits from that value, with the top most significant value being zero to push the colours into the darker half. The extra SRAMs require a decoder, but this has not yet been written. Instead the first SRAM’s Chip Select signal has been fixed in the asserted state.
I next soldered up the SVGA connector. Soldering up the resistor DAC was a fiddly experience; there are 18 resistors in a relatively small space. I probably should have tried to match the resistors using a multimeter, but neglected to do so. On top of that, my soldering doesn’t look great, but the picture the DAC generates is fabulous!
Prior to testing out the text mode I also had to solder up one of the 12nS SRAM sockets. Here’s a picture of the board when the above was taken:
The next job was to attempt to drive the display from the 68000. This too went surprisingly well. Initially I thought the previously observed data corruption was somehow solved, but after some time running the “stress test” of scrolling a message across the screen the odd corrupted character appeared.
Beside that problem the current VHDL implementation previously had another problem whereby the first column of text was shifted by one pixel.
Both of these problems have, I believe, been fixed.
I have solved the first problem using /DTACK to pause the processor between its write to the FPGA and the FPGA finishing the write cycle on the video SRAM. This will prevent it from performing a write to the FPGA if a video read cycle has prevented the FPGA from writing out that byte before it writes another one.
This does have one obvious side effect: after a write to video memory, five wait states are inserted. I can probably reduce this by tweaking the write state machine by using the MPU’s cycles more effectively.
The problem with the single pixel vertical offset on the first character column invloved a more interesting fix.
Essentially the character display works by reading from memory one character in front, or to the right of, the character that is currently being shifted out onto the display. The problem is at the top left corner there is no position to the left, so nothing has been read yet. The fix I’ve come up with is to shift the screen right. It is not actually shifted but rather the logic is changed to give 16 pixels to the left of the viewable area for reading the left-most character. The horizontal sync signal is similarly shifted right 16 pixels to the make the total (visible and invisible) pixel count the same; 800 pixels.
There remains one small inefficiency, or perhaps a better word would be quirk: the video memory is always being read, even when the displayed position is out of the visible portion eg. past the bottom of the viewed display. This continual reading creates an unnecessary conflict on the MPU’s ability to write into the video memory. At some point I will look at refining the design to correct this so read cycles are paused when the memory does not actually have to be read.
Here is a brief demo of the controller, driven by the 68000, being used to scroll a message on the screen:
Timing it out with the logic analyser, it takes 1.8us to copy a character from memory onto the screen. Not fantastic by any means: the whole screen could be filled with characters only around 115 times a second. Bandwidth onto the display is not a worry at the moment though as the volumes of data used by a full screen is relatively small, but it could start to be when bitmap video modes are used. For instance, a 640×480 screen at 2 bits per pixel would take 138ms to fill. There are, I’m sure, lots of optimisations, at both the software level and VHDL level, available to speed things up.
One further problem still exists with large writes into video memory: occasionally the display will flicker because the write is blocking the reads necessary to maintain the screen content. When this happens the read action sets a dummy value, which is the space character. The solution to this problem involves speeding up reads so they can done in a fraction of the time currently used. At the moment a read from memory takes half a character width worth of time, the other half being used to read from the font pseudo ROM in the FPGA, about 159ns. The speed of the memory used is 12ns, a big difference.
After satisfying myself that the VGA implementation was going to work well enough to at least be usable to display a text console, the next job was solder up the rest of the IO board.
I decided to forgo the usual testing-a-I-went approach and soldered up the whole board before trying out each part with my machine code monitor.
Here is a picture of the finished board sat atop the MINI000:
(Looking at the picture I see that one of the decoupling capacitors near the FPGA needs to be re-soldered, whoops.)
Before starting with testing the various IO ICs on the board, I decided I’d fix the very annoying JTAG header on the MINI000 board. It could only be reached when the IO board was removed, which was pretty annoying and added extra stress to both boards. I fixed the problem by replacing the vertical 10 pin IDC header with a right angled one. The MINI000 JTAG cable is the grey one underneath the SVGA cable in the picture above.
Testing the IDE interface was trivial as I already had code for it. Everything checked out well, though between ordering the PCB and testing it I found out that since I’ve only routed the “main” Chip Select (/IDECS1) line I cannot configure the IDE device to generate interrupts. This is a shame, but can be easily corrected on the next board. In terms of the boards performance, interrupts would make very little difference when only CompactFlashes are going to be used anyway.
Next up was the DUART, a Phillips SCN68681 (PDF). A quick test was made by turning the attached LED on and off. Again, no problems were noted. The hard wired input port also presented the correct value. Initially I struggled to get data from the UART header, attached to port B. This was until I realised that the images I’d found on Google image search all had a pin-out that didn’t matched my own USB TTL UART cables. To do a fairly complete test I modified the UART handling in the monitor to use this port, albeit temporarily. It looks like I’ll have good results attaching a MAXI09-style external keyboard to this board.
Finally the YM3812 (PDF). I used the same code I’d previously written when I had this part in some attached breadboard. After fixing a silly problem (ICs in the wrong sockets) I had some nice sounding notes from the attached speakers.
For fun I decided I’d have go at implementing a VGM player.
VGM is a register dump file which can be replayed into one of the many sound ICs supported by the format. Software-only players also exist, and in fact these days you can even play VGMs in a web browser. A popular website containing tunes to play is vgmrips.net. I duly downloaded a tune I thought was interesting, and armed with the sparse, yet understandable, VGM documentation and a hex dump of the tune I wanted to play to compare it with, I sat about writing a player routine.
For the added challenge I decided it would be interrupt driven. Sooner rather then later, I wanted to look at using interrupts on the 68000 and this seemed liked as good a time as any.
A counter/timer interrupt is available in some UARTs, including the two available to me with this setup. I chose the XR88C681 (PDF) in the MINI000 just because I find the Phillips data sheets harder to follow.
To route the interrupt I had to make a change the MINI0000 CPLD VHDL. When the interrupt signal from the DUART is active, the highest priority interrupt (IPL2, 1 and 0 are “000”) is set. This is autovector number 7, essentially the 68000’s NMI.
The timer interrupt is generated at close to 44.1Khz, the sampling rate for the VGM file format. This is fast for a 16Mhz computer system, but the 68000 seems able to cope and leaves just enough time, assuming the service routine has very little to do, for the processor to do useful work outside of the service routine.
For now, the VGM data is stored in raw disk sectors on the CompactFlash. At some point I will add, to the monitor, the ability to transfer data over a UART port and write it to memory.
A simple parser for the VGM header data structure, which does almost no checking currently, was written to determine the start of the register dump data. It also prints out some key header fields and their values. One tiny complication for the VGM reading code is that all values stored in the file are in little-endian format and thus need to be byte-swapped.
The interrupt handler reads and writes to a few shared variables. Theses need to be setup before the playing can start:
- Running: a flag that indicates whether the music should be playing or not.
- Data pointer: A pointer to the next byte to read out of the register dump stream.
- Delay counter: A counter used to implement delays: times when the handler should not write to YM3812 registers and should instead do nothing until the counter reaches zero.
Inside the Interrupt Service Routine the following steps are performed:
- A ticker counter is incremented so we can determine if the ISR is being run. This is independent of the VGM player.
- If the VGM player is not active, return from the ISR.
- Check for whether we are delaying processing of further playback by looking at the delay counter and decrementing it if it is non zero. In this case, we do not process the data stream.
- Otherwise get the pointer to the current data and read a byte from the data stream.
- The data stream is a command byte followed by 0 or more parameter bytes.
- 0x5A : A YM3812 register write: the two following bytes are the register address and the register data. Write these to the IC using an appropriate delay, after which return to step 4 to get the next command sequence.
- 0x61 : Delay. The following two bytes are a count of interrupt intervals which must elapse before the data stream pointer is advanced. These values are used in step 3, above.
- All other commands are ignored, except 0 which is used an End of File marker; the flag to say the playerdecrementing is running is cleared.
- Save the pointer so the next time the ISR runs we can pick it up again.
The VGM player works surprisingly well:
As usual, the code is on my github account if anyone happens to be interested.
To reduce interrupt load, the timer could be slowed by a factor of 2 or perhaps as much as 16, with the delay values adjusted accordingly, without much loss in precision. This would allow much more time to be available outside of the timer handler.
There is a noise issue with the board which is slightly irritating. The YM3812 output is not as clear as it could be. I’m not really surprised; I paid no attention to analogue aspects with this board.
In summary, I’m jolly pleased with my little IO board. It’s the first time I’ve done a bring up on any board without needing any hookup wires.
As usual, there are many, many choices for my next steps:
- I could start thinking about what kind of system software I want to write. I am leaning strongly towards porting MAXI09OS to the 68000, though I know it will be a large amount of work.
- I could look at porting an existing OS, like EmuTOS or even AROS, though I suspect I would be limited by the size of the EEPROMs in the MINI000 board.
- The possibilities for improvements to the VGA implementation are pretty massive:
- First up there are the aforementioned niggles to look at.
- Adding some kind of hardware-assisted scrolling could be interesting.
- Read-back of the video memory would be useful to have.
- Coloured text could be fun to do: an attribute byte added either interleaved with the character array or in a different block.
- Bitmap modes: the starting point would be a simple 640×480 1 bit per pixel mode with a static black and white palette.
- I could start work on the keyboard. It’ll be electrically the same as the MAXI09 keyboard, but self-contained. For the experience to be gained, I’m going to use Surface Mount parts for the small PCB containing the controller and connectors.
- Yet another option is to jump ahead and start planning for a MAXI000 board. I have a few plans in my head, and it’s shaping out to be very interesting.
So, it’s all a lot of fun! The hard part is deciding what to look at next…