Oberon system implemented on an affordable FPGA board

Original author: Niklaus Wirth
by Niklaus Wirth
Professor (retired)
Swiss Federal Institute of Technology (ETH)
Zurich, Switzerland

In 1988, Jurg Gutknecht and I completed and published the programming language Oberon [1, 2], which was the successor to two other languages, Pascal and Modula-2, which I had previously developed. The Oberon language was originally designed by us as being more rational and effective than Modula-2, which made it easier for students of the academic education system to master computer science. Not stopping there, in 1990 we built a modern operating system (OS) Oberon for workstations, using windows and word processing capabilities. Then we published a book revealing the details of both the Oberon compiler and the OS of the same name. The book, entitled "Project Oberon", included the source code of the system.

A few years later, my friend Paul Reed suggested I publish a reprint of the book, due to its importance for studying system architecture and giving a good starting point for those who want to build reliable systems from scratch.

However, a serious obstacle arose. The original compiler was created for a processor that has already disappeared from the market. So I decided to rewrite the compiler for the modern processor. But in the course of a little research, I could not find a processor that fully meets my criteria of clarity, regularity and simplicity. So I had to design my own processor. This idea was realized thanks to the modern PPVM chip (user programmable gate array, FPGA), which allowed me to create hardware just like creating a software system. Moreover, the choice of Xilinx® FPGA gave me the opportunity to remake the system without deviating much from the original project of 1990.

The new RISC processor is implemented on a low-cost Digilent Spartan®-3 board with a single-megabyte static memory module (SRAM). All my hardware improvements concerned the mouse interface and the SD card, which replaces the hard drive in the old system.

The book and the source code of the entire system are available on the projectoberon.com website [3,4,5]. A separate S3RISCinstall.zip file is also available there . It contains instructions, an image of the file system for the SD card and bit configuration files for the FPGA (in the form of PROM files for the flash memory of the Spartan-3 board), design parts for the hardware interface of the SD card and mouse.

RISC processor

The processor is represented by the RISC5 Verilog module and consists of an arithmetic logic unit (ALU), an array of sixteen 32-bit registers, and a control module with an IR instruction register and a PC program counter (see more details - approx. Transl.).

The processor processes 20 instructions: four for moving, shifting and rotating; four for logical operations; four for integer arithmetic; four for floating point calculations; two for memory access and two for branching.

RISC5 is imported from the RISC5Top context containing the interfaces for various devices mapped to memory and SRAM (256 MB x 32 bits). The whole system (Fig. 1)
Fig. 1. System diagram with Verilog modules.

contains the following Verilog modules (the number of lines of each module is shown):
RISC5Topenvironment194
Risc5processor201
Multiplierinteger arithmetic 47
Divider24
FPAdderfloating-point arithmetic98
FPMultiplier33
FPDivider35
SPISD card and transmitter / receiver25
Vid1024 x 768 video controller73
PS2keyboard25
Mousemouse95
RS232TRS232 transmitter23
RS232RRS232 receiver25

I mapped a black-and-white VGA display into memory so that it occupies 1024 x 768 x 1 bit per pixel = 98.304 bytes, essentially 10 percent of all available memory in 1 megabyte. Access to the SD-card, which replaced 80 megabytes from the original system, is carried out via the standard SPI interface, which accepts and serializes bytes or 32-bit words. The keyboard and mouse are connected via the standard PS-2 serial interface. In addition, there are serial asynchronous RS-232 cables and a multi-purpose 8-bit parallel I / O interface. The RISC5Top module also contains a millisecond counter.

Oberon operating system

The OS software includes a kernel that includes a memory allocator with a garbage collector, a file system with a bootloader, a text system, a viewer system, and a text editor.

A module called “Oberon” is the central task manager, and “System” is the basic command module. An action is called by clicking the middle mouse button on the text of the form “MP” in any display, where P is the name of the procedure declared in the module M. If M is not available, it is automatically loaded.
Most text editing commands are called by ordinary mouse clicks, in which the left button serves the caret, marking the current position in the text, and the right button is responsible for highlighting the text.

The Kernel module includes disk-store management and a garbage collector.
Viewers are tiled and do not overlap. Standard layout displays two vertical tracks with an unlimited number of viewers. You can increase or decrease them, as well as drag them to the title bar. In fig. Figure 2 shows the user interface on a monitor connected to a Spartan-3 board with a keyboard and mouse.


Fig. 2. The user interface on the monitor and Spartan-3 bottom right.

A loaded system occupies 112.640 bytes in modular space (21 percent) and 16.128 bytes in the heap (3 percent). It consists of the following modules (with the number of lines each) shown in Fig. 3:
Kernel271 (inner core)
Filedir352
Files505
Modules (loader)226
Viewers216 (outer core)
Texts532
Oberon411
MenuViewers208
Textframes874
System420
Edit233

It is worth noting that loading the system at startup or restart takes only 2 seconds, including scanning the file directory for garbage collection.

Oberon

Compiler The compiler is built into the system and uses a simple recursive top-down parsing method. Compiler activation is done using the ORP.Compile @ command. The parser receives characters from a scanner that processes identifiers, numbers, and special characters (such as BEGIN, END, +, and others). This design has proven its suitability and elegance in many applications and is described in my book Compiler Construction [6,7].

The parser calls the procedures from the code generation module, which directly add instructions to the code array. Branch instructions are generated by jump addresses at the very end of compilation, when all jump points are already known.

All variable addresses are calculated relative to the base register. This is R14 (stack pointer) for local variables (set when entering the procedure in runtime), or R13 for global and imported variables. Base addresses are loaded upon request from the global module table, whose address is stored in register R12. Register R15 is used for return addresses according to the RISC architecture. The remaining registers, R0 - R11, are available for evaluating expressions and passing procedural parameters.

The entire compiler consists of four relatively small and efficient modules (the number of lines of each is indicated):
ORPparser968
ORG code generator1120
ORBbase def435
ORSscanner311

The compiler occupies 115,912 bytes (22 percent) of the modular space and 17,508 bytes (4 percent) of the heap (before compilation). Its source code is about 65 kilobytes in size. Compiling the compiler itself takes only a few seconds on a 25-MHz RISC processor [8].

The compiler always generates checks for array indices and NIL pointers. This generates traps (trap, trap - approx. Transl.) In case of violation. This technique guarantees a high level of protection against errors and damage. In fact, the integrity of the system can only be violated by using operations of the SYSTEM pseudo-module, such as PUT and COPY. These operations should be used to a limited extent, only in the device driver modules and can be easily found by the name SYSTEM in the import list. The whole system is programmed on Oberon itself, without the use of assembler codes.

I chose the Digilent Spartan-3 board because of its affordability and simplicity, which makes it suitable for educational institutions acquiring whole sets for classes. The big benefit is also in the presence of static RAM on the board, which allows you to connect (interfacing) directly (and even read bytes). Unfortunately, the latest boards use dynamic RAM, which, although more capacious, but more difficult to connect, requires additional circuits for updating and initialization (calibration). Such circuitry can be no less complex than the entire processor with static RAM. Even if the controller is delivered on a chip, it violates our principle that everything should be available for control.

Thoughts at last

More than 40 years ago, C. Hoar noted that in all branches of science and technology, students are influenced by a large number of examples of serious structures before they gain their own experimental experience. Programming and design programs emphasize this paradigm. Students have to write programs from the very beginning, instead of studying various patterns.
The reason for such a terrible situation was that there was almost no literature with qualified examples. Therefore, I decided to rectify the situation and wrote the book “Algorithms and Data Structures” in 1975. In the future (together with J. Gutknecht), as part of teaching the course of operating systems, I designed the Oberon system (1986–88).
After a while, the teaching of programming did not receive a noticeable improvement due to the fact that the systems were dramatically complicated and increased in size. Although the open source has received recognition, he could not change the situation, since most programs are created only to run them as soon as possible, and not for a better understanding of them by a person.
I continue to make bold assumptions that all programs should be created not only for the computer, but also for human understanding. They must be available. This task is much more complicated than creating executable programs, even if they are correct and efficient. This implies that there should be no assembler inserts.

The result of ignoring the human factor leads to the fact that there are not very carefully designed applications everywhere, brought to the working state by debugging, sometimes with gloomy consequences. To achieve comprehensibility, it is worthwhile to adhere to simplicity and order, refusing unnecessary decorations and, avoiding bells with whistles, to distinguish between conventional and convenient.

The small size of such systems shows how small you can achieve a lot. The dimensions of the Oberon OS are ridiculously small in comparison with modern operating systems, although it includes a file system, a text editor and a window system. A side effect is that a few simple rules are very easy to learn for future reference.

And finally, the advantage of brevity is that you can safely build such a system without fear of unknown features such as backdoors. This is an essential feature, very important for systems critical to security issues, given the increasing danger of attacks on system integrity. It is equally important that the hardware of our system does not contain any hidden parts. No one can give guarantees for systems built on a foundation that is inaccessible to understanding in its entirety.

Thanks

I am very grateful to Paul Reed for his invaluable contribution. He suggested that I edit the book “Project Oberon” and also proposed to re-implement the entire system on FPGA. Paul was an inexhaustible source of encouragement. It was his idea to replace the drive with an SD card and he provided SPI, PS-2 and VID Verilog interfaces.

References

1. www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.Report.pdf
2. www.inf.ethz.ch/personal/wirth/Oberon/PIO.pdf
3. www.inf.ethz.ch /personal/wirth/ProjectOberon/index.html
4. www.inf.ethz.ch/personal/wirth/Oberon/PIO.pdf
5. www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.Report.pdf
6. www.inf.ethz.ch/personal/wirth/CompilerConstruction/CompilerConstruction1.pdf
7. www.inf.ethz.ch/personal/wirth/CompilerConstruction/CompilerConstruction2.pdf
8. www.inf.ethz.ch/personal/wirth/ProjectOberon/PO.Applications.pdf (Ch. 12)

Appendix

Lola's language and its translation in Verilog



The hardware-description language (HDL), named Lola, was defined in 1990 to teach the basics of hardware design. It was a time when text definitions began to replace circuit diagrams and at that time the first FPGAs became available, although they had not yet reached the industrial level. For Lola, a compiler was created that generates bit files suitable for loading into FPGA. Bit file formats are disclosed by Algotronix, Inc. and Concurrent Logic Inc. Both formats made it possible to work with cells of fairly simple structures that are optimal for automatic wiring.

According to the results of my project of reworking Oberon for FPGA, an idea arose to revive Lola as well. Since Xilinx FPGA cells are more complex, we did not dare to make efforts to implement placement and wiring, regardless of the fact that Xilinx refused to open its patented bit file format.

The obvious decision was to build such a Lola compiler that would not generate proprietary bit files, but would translate into a language for which Xilinx provides a special tool. We chose Verilog. This solution implied a somewhat extravagant workaround: first, the Lola module must be parsed, then translated, and eventually parsed again. At all these stages, we must ensure that the Lola compiler has proper error control and type checking capabilities.

To push the development of Lola-2, we needed to reformulate all the modules of the RISC5 processor on Lola. Which was done.

Language Lola

Lola is a small, laconic language in the style of Oberon (see www.inf.ethz.ch/personal/wirth/Lola/Lola2.pdf ). For brevity, we will show here only one example of text on Lola (Fig. 1). The unit of source text is called the module. Its header defines the name of the module, the names and types of input and output parameters. After the header is a section for declarations of local objects, such as variables and registers. Next is the section for determining the values ​​of variables and registers. BYTE defines an array of 8 bits.

MODULE Counter0 (IN CLK50M, rstIn: BIT;
	IN swi: BYTE; OUT leds: BYTE);
TYPE IBUFG: = MODULE (IN I: BIT; OUT O: BIT) ^;
VAR clk, tick0, tick1: BIT;
	clkInBuf: IBUFG;
	REG (clk) rst: BIT;
	cnt0: [16] BIT; (* half milliseconds *)
	cnt1: [10] BIT; (* half seconds *)
	cnt2: BYTE;
BEGIN leds: = swi.7 -> swi: swi.0 -> cnt1 [9: 2]: cnt2;
	tick0: = (cnt0 = 49999);
	tick1: = tick0 & (cnt1 = 499);
	rst: = ~ rstIn;
	cnt0: = ~ rst -> 0: tick0 -> 0: cnt0 + 1;
	cnt1: = ~ rst -> 0: tick1 -> 0: cnt1 + tick0;
	cnt2: = ~ rst -> 0: cnt2 + tick1;
	clkInBuf (CLK50M, clk)
END Counter0.

Fig. 1. The source text on Lola shows the counter of seconds and milliseconds displayed on the board indicators.

Lola

Compiler The compiler uses a simple recursive descending parsing method. It is activated on Lola's selected source code with the LSC.Compile @ command. The parser receives characters from a scanner that processes identifiers, numbers, and special characters (such as BEGIN, END, +, and others). This design has proven its suitability and elegance in many applications and is described in the book Compiler Construction (Part 1 and 2).

Instead of generating Verilog texts directly on the fly, the parser first creates an operator tree, which is more suitable for further processing. This approach has the advantage that any desired output can be easily generated by a suitable translator. One of these is the translator in Verilog. The first LSV.List command is outputfile.v. Another team can translate to VHDL or simply output the tree. The third one can generate a netlist for further processing by the scout.

Thus, the entire compiler consists of at least four relatively small and efficient modules:
Lssscanner159
LSBbase52
LSCcompiler / parser503
LSVVerilog generator215

Transmission instructions from Lola to Verilog can be found here: www.inf.ethz.ch/personal/wirth/Lola/LolaCompiler.pdf .

Differences between software and hardware “programs”

In the past, a lot of effort has been made to make HDL languages ​​look like “regular” programming languages. In addition, HDL have “doubles” among other PLs, adapting to their style. For example, Verilog came from C, VHDL from Ada and Lola from Oberon. But we believe that it is important to see the fundamental differences between these two classes, in particular in the presence of syntactic similarities, or even identities. What are these fundamental differences?

To simplify the explanation, we limit our analysis to synchronous circuits - that is, those in which all registers are tied to a single clock. In general, synchronous circuits are a good architectural paradigm, which should be followed, if possible.

Further, it is obvious that all elements of the circuit work simultaneously, literally at the same time. Each variable and each register are defined by one and only one expression (combinational circuit). Multiple assignments do not make sense. We can easily imagine each HDL program enclosed in a large infinite loop, since assignments to registers and variables occur every cycle.

John von Neumann's idea of ​​introducing a sequencer-based processor architecture was brilliant. The sequencer contains a register of instructions according to which certain patterns are selected in each cycle and the others are ignored, which leads to the skillful reuse of various parts of the ALU. Measures or steps are sequential in nature, so it is possible to reassign values ​​to variables according to how the program counter relates them to specific places in the program and in the sequence of instructions. The sequencer idea made it possible to run huge programs on relatively simple circuits.

So, Lola-2 is HDL in the style of YP Oberon. The compiler presented here translates Lola modules into Verilog modules. The advantages of Lola are both in the simple and familiar structure of the language, and in emphasizing the compiler for type checking and advanced error diagnosis. A complete set of modules for the RISC processor described on Lola: www.inf.ethz.ch/personal/wirth/Lola/index.html

Also popular now: