Ville is a computer science student in Finland. He can be contacted at email@example.com.
Menuet is a small multitasking real-time operating system with a graphical user interface; see Figure 1. Written entirely in x86 32-bit assembly language, I designed Menuet to fit on a single 1.44-MB floppy diskette, requiring only an 80386 (or greater) CPU, 32 MB of RAM, and mouse. Menuet provides protection for memory and code, runs at 16 million colors and at 44.1-KHz sound, and currently supports the Fat12 and Fat32 filesystems. Menuet is freely available at http://www.menuetos.org/ and from DDJ (see "Resource Center," page 5) and distributed under the GPL. The system includes a 32-bit assembler, text editor application, demos, and other relevant information.
Among my design principles is the belief that the more complex an operating system is, the more likely it is to have bugs. That's why most of Menuet's functions are implemented as in a monolithic kernel, rather than a microkernel (see Figure 2). And since complexity can lead to poor performance, another of my goals with Menuet was to get rid of the built-in layers between applications and hardware that slow down and complicate programming.
Developing Menuet with 16-bit assembly language would have been a very complex task. However, 32-bit assembly language, with its six registers and linear memory access, makes programming a relatively straightforward task. Because of this, if you want to use other operating system applications in Menuet, the best place to start would be by writing a layer outside the OS, much like Wine has done with the Win32 API.
Menuet lets you use both event-based and real-time processing. System functions are accessed using int 0x40 with the function number in register eax. Other parameters are in other registers or a memory table. When creating Menuet-based applications, your main focus should be on the system_event function. System events can include buttons, keys, IRQs, and the like. You have three different accesses to events: wait for event (function 10), ask for event without wait (function 11), and time limited wait (function 23). By the time an event happens you will receive the event type in eax.
Functions 10, 11, and 23 return the event type in eax. For a key press it's 2, for a button it's 3. When an event_button occurs, you can ask for the button number from the system via function 17, which returns with the button ID saved in ah. If there is a key in buffer, you can ask the ASCII value with function 2, which returns the ASCII value in ah. If there are no events in buffer, functions 2 and 17 set al to 1.
There are three event types that are set as the default: key press, button press, and window draw. Applications are expected to handle these three by default. When the window_draw event occurs, the OS is requesting the application to redraw its contents since there has been some activity on screen and some parts of the application has to be drawn.
The place to start when programming the Menuet API is to draw the window so that you have a canvas onscreen. The draw_window function starts with acknowledging the OS for window draw. Next, use function 0 with appropriate parameters to set the window position, size, and colors. This function draws the basic UI (text and buttons). Buttons are set with function 8, which takes the color, coordinates, and button ID number as inputs. When the button is pressed, the OS acknowledges the application with a system_event and the button ID can be fetched. Text is drawn using function 4, which takes position, text, and color as input.
Data and code can be mixed, and you can use self-modifying code since the segments are set to the same base address. Overall, the general coding scheme for application involves assembly coding similar to other environments.
Among my future plans for Menuet is to enhance compatibility, add support for TCP/IP protocol, and port the kernel to the Flat Assembler (FASM; http://www.programmersheaven.com/zone5/code25/) so that external compilers will no longer be needed.