Requirements Analysis.
Every new project starts with an empty document, a blank sheet. It’s a unique moment where you have complete freedom. As soon as you put something down in the document, you’ve made a choice and your options become limited. With each subsequent choice, you limit yourself more, until there are no more choices to make, at which point the project is complete. So, in a way, this post, along with the previous one, are the two most important posts of the whole project. We’re making our first choices, setting the direction of this project.
Let’s go over the project’s goals/requirements and clarify a bit what they mean.
Simplicity
Simplicity will be a strong guideline when making design choices. For instance, it may mean that we decide against a popular-but-complex processor in favor of a more obscure-but-simple processor.
It is hard to make something simple. The Simplicity requirement will make system design harder, not easier. For a case in point, see below.
Deterministic Behavior
Designing a deterministic system is more complex than designing a system that allows some slack in the completion of operations. However, once such a system is in place, it becomes much easier to reason about it and design applications on top of it, especially applications with real-time requirements. For instance, it would be pretty cool if the system is designed so that racing-the-beam becomes possible, i.e. time actions within an application’s main loop so that they take place on a specific screen scan line and a specific column on that scan line. Think Commodore 64 split raster bars and sprite multiplexing.
Note that deterministic behavior must be guaranteed only when required by the application. Less deterministic operations are perfectly acceptable when the application does not require full deterministic behavior. E.g. a deterministic application runs from Block RAM with known, fixed memory access latency, while a non-deterministic application may run from bursty external memory.
One consequence of the Deterministic Behavior requirement is that bus arbitration should be done using fixed time slots to be able to guarantee fixed timing, latency, and bandwidth to each bus master.
Single User / Single Tasking OS
We won’t be running Linux or any other multitasking OS for that matter. The platform will only run one application at a time and that application will be fully in charge of the entire system.
A Single User / Single Tasking OS will provide the following services:
-
A console CLI shell allowing user and scripted access to:
- navigate the file system
- load/save software images to/from memory
- copy/move/delete files
- execute (transfer control to) applications in memory, optionally passing in command-line arguments
- peeking and poking into memory
- File System I/O kernel routines
- Console I/O kernel routines: Input from a physically attached keyboard, output to a physically attached screen.
- UART I/O kernel routines
- Discovery and enumeration of hardware components. See Modular Architecture below.
Not Boot-to-Basic
I don’t want to be pinned down to, or give preference to, any particular interpreted language, so we’re not going going to Boot-to-Basic. We’re not going for full-retro boot-to-Basic.
I would like to allow open support for multiple interpreted languages by letting the application image indicate in which language it’s written, e.g. by specifying on the first line the path to the interpreter to use, as commonly used in Linux scripting: #!/usr/bin/python, #!/usr/bin/ulisp, …
It should also be possible to directly execute binary images of course.
Modular Architecture
I imagine a reference configuration to which hardware components can be added or from which components can be removed. Applications should be able to discover, with the help of the OS, whether a certain component is present or not.
Partial FPGA Reconfiguration
It would be very cool if a hardware component can be incrementally loaded into the FPGA, using Xilinx’ DFX (Dynamic Function eXchange) feature. This would allow applications to be packaged along with specific hardware components (e.g. accelerators or peripherals) on which they depend.
I’m considering this feature a stretch goal for the project.
Target Hardware and Peripherals
I currently have an Arty A7 35T, with the following PMODs for peripherals:
- Pmod MicroSD: microSD Card Slot
- Pmod PS2: Keyboard/mouse connector
- Pmod AMP2: Audio Amplifier
- Pmod VGA: Video Graphics Array
- Wii Nunchuck Adapter
I suspect that over time the project will outgrow this setup and I might move up to the Nexys A7-100T, also from Diligent. Compared to the Arty A7 35T, Nexys A7-100T has:
- A bigger FPGA: More logic slices and more Block RAM.
- Onboard microSD card connector
- Onboard PWM audio output connector
- Onboard PDM microphone connector
- USB HID for keyboard and mouse, with a clever adapter so keyboard and mouse present themselves to the FPGA as PS/2 devices.
- VGA connector
Interesting Links
https://www.linusakesson.net/programming/poems-for-bugs : A great talk from Linus Akesson about C64 coding, explaining why to this day people are still compelled to develop games and demos for this wonderful machine.