In a previous post, I had introduced the Oberon programming language, and in a follow up the Oberon system and the custom RISC processor. Now I was going to get my hands dirty, even though I had no idea I would when starting out.
A Different Mindset
With a conventional microprocessor, interrupts are central to implement many real-time system features. A process writes to a buffer and yields control to allow other processors to run, while a corresponding interrupt handler empties the buffer sending data to a peripheral. That sort of thing. When I first experimented with the interrupt of Oberon’s RISC5 processor, I ran into some issues.
Chris of Astrobe kindly connected me to Paul Reed, one of the co-creators of the Oberon system. Of course, Paul could explain the cause of my problems, but also gently and kindly slapped my wrist, pointing out that with an FPGA at my disposal I should assume a different mindset: avoid interrupts if possible, and rather implement a solution in the FPGA – which extends the solution space from the software into the hardware. He’s right. Non-trivial interrupt setups can get cumbersome quickly, not least with an eye on the overall robustness of a system or program.
Inside the FPGA
Soooo… I started to get into FPGA design. You know, hardware design. I haven’t done this since my earliest days as engineer, when I designed mixed digital-analogue electronic boards for the AXE telephone exchange. Back then, it meant drawing the circuits as a schematic. Now it’s Verilog, a language that defines the logic. Studying the existing Verilog code of the RISC5 processor, from CPU to peripheral devices, helped me to get started.
The picture to the right shows the Arty-A7 board, the FPGA chip is the labelled one, mounted slanted.1
As an example, my code for a simple watchdog timer, ie. a device that needs to be reset periodically by the software, as otherwise it will cause the system to restart, or take other corrective measures. In real-time software, this facility is used to detect faulty behaviour, for example an infinite loop, or a process that takes too long to do its work.
Verilog may look similar to a programming language, but it’s pretty different, as it defines hardware logic, where everything is happening concurrently. The statements are descriptive: even though listed sequentially, statements are in fact “executed” at the same time.
module WATCHDOG1 ( input rst, clk, tick, input wr_timeout, input [15:0] data, output bite ); reg [15:0] timeout = 0; reg [15:0] ticker = 0; wire stop = (timeout == 0); assign bite = (ticker > timeout); always @ (posedge clk) begin timeout <= ~rst ? 0 : wr_timeout ? data : timeout; ticker <= stop ? 0 : wr_timeout ? 0 : ticker + tick; end endmodule
A quirky toolset, provided by the maker of the FPGA, Xilinx, takes this text, and creates a binary file to actually program the FGPA via a USB connection to the board. Kindly, Xilinx makes a limited version of the tools available for free. A licence would be about 4k USD. Ouch. The free tools provide the full functionality, and are only limited as regards which FGPA models they support.
The tool is actually pretty sophisticated in its core. It first runs a step call synthesis, where it checks for obvious errors, such as an input driven by two signals, and creates a list of needed logic gates, look up tables, flip-flops, logic shifters, and so on, as well as their connections. The subsequent phase, called implementation, then physically places these elements on the FPGA chip, routes the connections in-between, and runs several checks. The most important check is for the timing, ie. if the signals arrive within the limits feasible for a reliable operation at the given clock rate.
A dreaded outcome of these tests is a severe warning that your design misses these limits by, say, 0.157 nanoseconds. The tool tries to do its best as regards placement and routing, it also provides different corresponding strategies. It will try a certain design, test, then backtrack if not good enough, and try again in a different way. But when it fails nonetheless, you have to back to the drawing board, ie. fiddling with your Verilog code.
The whole process from synthesis to implementation to creating the binary bitstream file to program the FPGA from the Verilog sources takes a few minutes for the whole RISC5 system-on-a-chip, ie. CPU, RAM, PROM, and all the peripherals, on my elderly i7-7700K based PC (4.5 GHz).
There’s also a simulator to run a logic module purely in software, which allows to check each and every state and signal. I am using this facility often to verify and debug my Verilog designs. Yes, you can, and should, also run tests in the real hardware, but if something does not work as intended, it’s not trivial to track down the problem – inside the FPGA chip.
It’s possible to pull out some signals on externally accessible pins and ports, and hook up a logic analyser and oscilloscope, but there are obvious limits. An example would be the state of a 32-bit bus or register: that’s simply too many required external lines, both for the chip’s connections as well as the logic analyser. In the simulator it’s also easier to create the various valid and invalid input data sets to explore and test the behaviour of a module.
I have been hooked by this new possibility to create or extend a system: always consider to put part of a solution into the hardware. Sometimes I am disappointed if some idea does not require a hardware extension, but can easily implemented in software only. Just kidding. Well, half-kidding. See, what happens in the FPGA runs in parallel to the software in the CPU. It’s like having a small army of co-processors, in addition to the CPU. Oberon makes it easy to interact with the hardware via memory-mapped IO. For example, with a buffered SPI device the software can fill the buffer, then go on about some other task, while the hardware logic empties the buffer in parallel. No interrupt handlers and software required.
Putting part of a solution in custom hardware can significantly simplify your software, with positive effects both on complexity and run-time efficiency. Take process scheduling for example. With a time-triggered architecture, the scheduler needs to keep the time for each process, periodically updating a corresponding timer. This time-keeping can easily be done in the hardware. I have implemented a corresponding process controller, which only informs the software when the time is up to run a process, thus relieving the scheduler from is periodic time-keeping duty. The processes’ state and priority handling are still done in software. I have been thinking about pushing even more of this into the hardware, but have left this exercise for some future tinkering.
Since I started to get into the possibilities of the FPGA back in May, when I didn’t even know how to spell Verilog, I have now implemented a few modules, such as:
- the aforementioned process timer controller
- a process controller to respond to signals from peripheral devices
- a flexible RAM module
- a simple multi-channel interrupt controller
- various extended peripheral devices (SPI, RS232)
- the above watchdog
The latest experiment is to put two RISC5 CPUs on the same chip, including a messaging channel in-between. Works pretty neatly.
The Oberon system is focused on human users. Priority is given to execute commands. However, I am a real-time and control system nerd, ie. interested in systems and solutions that work autonomously to make stuff happen in the real world, without or with minimum user interaction. Think Apollo Guidance Computer, where the astronauts start programs to initiate different phases of, say, the moon landing, but thereafter the computer again takes control to continuously compute the position vector and fire the main engine and the thrusters to keep the spacecraft on the required trajectory.
My project is to turn Oberon’s focus around, from human-centric to control-centric, just for the fun of it. At some point, in July or so, I realised that I really need to document what I am doing. Mulling over the different possibilities to do that, I realised that I could do that with a website. And why not in the open, ie. with a publicly accessible site?
So here you go: Oberon RTS.2
Not yet described on the site is my most recent and on-going work, namely on task-based processes and restart protection.
Serious About Software
Alan Kay reportedly said: “People who are serious about software should make their own hardware”.
I guess that makes me finally serious about software. Just kidding.
In the back you see the hardware part of the logic analyser, which also uses an FPGA. The software part runs on the PC. In the Old Days, a multi-channel logic analyser cost several thousand Euros, this one is about 250 Euros. ↩︎
As you see, lazy me simply adopted the Hugo framework from this site. Both sites use the same framework, but I needed a few changes and extensions to make it work for both use cases. Configurable, of course. Without FPGA-support, alas. ↩︎