Before I started on this project, there was already a significant question I had to confront: What software is going to run on this?
Integration with the Arduino IDE is beyond what I can undertake myself. Instead an experience more like an AVR with AVR-GCC would be a more appropriate starting point given the chosen form factor.
So basically I just want a simple main() with an interrupt_handler() in the event interrupts are needed. So how do I get from that requirement to something that works?
The 8086 is a microprocessor, not a microcontroller like the AVR, so the software side of things is quite a bit more involved. Very quickly I find myself grappling with some fairly complex concepts which you wouldn’t have to give a fig about on an AVR, i.e. assembly bootstrapping routines, linker scripts, code relocation, memory maps, vectors and so on.
Annoyingly, the internet is not exactly bristling with examples of how to do this kind of thing on an x86 system, because it’s seldom done outside of the aerospace/military sectors, who commonly maintain “no-BIOS” (non PC) legacy embedded systems using these processors. Additionally, these people tend not to frequent stackoverflow.com
The second big challenge is that it’s pretty tough to debug when it goes wrong, not to mention that I’m learning 16-bit x86 as I go. It was only a couple of weeks before I found myself reaching for the big guns
C Compiler Selection
I had initially hoped that GCC had an x86-16 backend but alas it doesn’t, and why would it?
It was written for Linux, and Linux does not run on 16 bit processors. EDIT: Apparently it wasn’t written for Linux, but did support 16 bit processors a really long time ago.
So instead I had to dig around in the archive a little more. The best x86-16 C compiler is Open Watcom which is an open source cut of the proprietary WATCOM compiler, which was mostly used for creating MS-DOS applications. Specifically I needed version 1.7a which (as I’ve discovered) is the last version who’s linker works for embedded systems.
The first question any 16-bit buff is going to be asking, is which memory model I’m using for this project?
The answer: Small.
Small gives 64KB of code space, and another 64KB of data. I felt that Small was a good compromise between performance, what would actually be needed and utilisation of the 512KB of RAM I’ve put on the board.
The other advantage of Small is executional simplicity and ease of troubleshooting. Having the segment registers ticking over like the meter in an Egyptian cab makes things right pain in the arse to debug.
There is nothing preventing the usage of a different memory model – the Bootrom, for example; while developed using the Small model (and ought to stay that way), doesn’t give a fig about what model the application uses, and therefore leaves nothing obstructing the development of an application using a different model. Doing so however, would require a comprehensive understanding of the 8086, and the Watcom toolchain; and I’m not going to be doing it.
SPI Flash memory usage
As I’ve mentioned, the onboard flash chip is important as it’s where 8OD stores its user data, and application software. The 1 megabyte is separated into two 512KB halves. The top half stores a streamlined binary copy of the users .HEX file, outputted by Open Watcom, and the bottom 512KB stores user data.
The whole chip is readable and writeable using the programming utility, and the running system. It is the responsibilty of the Bootrom code contained in the EPROM to read, write and bootstrap from this chip.
It would have been nice to have an i8259 or some implementation of it, but realistically, I couldn’t accomodate it.
Instead the Non Maskable Interrupt is used for everything, except it is maskable by the GINT bit in the CPLD. Even more confusingly, NMI is edge triggered, whereas everything entering the CPLD is level triggered?
This is another lovely quirk of my design. When level interrupts first assert, they have an edge, which can set off NMI, but the problem is that if there is still a level interrupt condition when the ISR exits, or one appeared at the end of the ISR, it won’t re-trigger NMI.
I’ve kludged around this by physically masking the NMI signal from the CPLD when the ISR starts, and unmasking it when the ISR exits. In the event there is still a level interrupt asserted, this artificially creates another edge, which re-triggers NMI, causing the CPU to vector straight back into NMI’s ISR, where the software can read the CPLD’s STATUS register to examine which interrupts are active.
This scheme has a slight performance hit as a few extra instructions are required in the prologue/epilogue of the ISR, but in practise it’s not unacceptable and I’ve not found any problems with it yet (touch wood).
This is approximately how interrupts work on an 8051 with the exception that no software bodge is needed to translate level interrupts into edge interrupts.
Of the people I’ve told about this so far, the first question I get is: Isn’t something that old going to be slow as all heck. The answer: Yes. Even with blistering speeds of 10MHz, the 8086 has no cache, and doesn’t get much done in less than 10 clock cycles, leaving it with a MIPS of below 1, whereas a 16 MHz AVR theoretically is 16 MIPS.
In practise the 8086 does manage to claw some performance back by being CISC, and by having a 16-bit data path, and 8OD is designed to take full advantage of this (with exception of UARTs and SPI which are 8-bit peripherals).
Having said all this though, it still makes a pretty respectable microcontroller, more than powerful enough to do all of those silly things we do with Arduino’s.
Has it got a BIOS?
Yes and No, but for the most part: No.
BIOS is a heavily misused term. Most people think of anything that runs from that little flash chip before the OS boot as “BIOS”. 8OD, by proper definition, has no BIOS, and here’s why:
In a Nutshell, BIOS is an old blob of basic device drivers, used during runtime, by operating systems like MS-DOS.
It doesn’t necessarily have anything to do with the process of bootstrapping the PC, or providing the setup menu that most are familar with. All of the above can be done by a piece of software that is most definitely not a BIOS, and that is the case for 8OD.
It is this way for 8OD because its bootrom does not provide any drivers which can be utilised by the application at runtime. Instead, once handed over, the application is on its own. This model is universal for almost all embedded systems.
Could it run DOS?
A bespoke BIOS would have to be written but it may just be possible. If anything were to prevent it, it would be lack of PC compatibility, more than it would lack of more familiar things (keyboard/VGA etc).
In theory, this should not be an issue as the interface between DOS and BIOS is generally fairly abstract, meaning that hardware can be implemented arbitrarily.
In practise there’s bound to be something that demands standard PC hardware i.e. the i8042 keyboard controller or the i8259 interrupt controller, and such things are not going to get far.
I do not plan to undertake something like this myself.
What I have so far
After burning almost 2 months of all available spare time, I managed to get a working skeleton system with drivers for all of the onboard hardware, as well as a simple serial bootloader, which loads and can boot from code in the onboard SPI flash chip. The bootrom runs from the large EPROM which currently does nothing else.
In addition to the C code which runs on the board, there is a C# application which is needed to parse the .HEX file from Open Watcom and convert into a primitive executable format which the bootrom knows how to parse. The application also performs the serial based flash programming.