TL;DR: even if you’re not being pragmatic, you probably don’t need to.
One of the things I have been thinking about while starting to work on
moss
again is whether I should implement
one of the many RISC-V flavors, or whether I should design
an entirely new instruction set architecture (ISA). Designing a new one might
seem like the ultimate bike-shedding effort, and if my immediate goal was
getting something useful into production, I almost certainly would not embark on
the journey. However, there are a few reasons why designing a new ISA is
compelling to me:
- It forces me to think about the pros and cons of existing ISAs and decide which design choices I want to emulate vs. eliminate.
- It will undoubtedly result in discussion and iteration, which will in turn result in artifacts that can be used as educational resources.
- There are potential opportunities for optimization.
These reasons could essentially be boiled down to a desire to understand what it takes to design an ISA from scratch. While there are many, the most obvious reason for not designing a new ISA is leveraging an existing software ecosystem. Updating compiler toolchains, debuggers, and emulators to support a new ISA is a monumental effort that typically takes many people a number of years.
Perhaps the real decision that I am making is whether I want to support existing
software ecosystems. moss
is characterized as a vertically-integrated
computer, and an extreme interpretation could be that you have to use the moss
stack to work with the moss
computer. One could even argue that a stable ISA
isn’t needed at all in this world; there would only be an internal intermediate
representation used by the toolchain that turned whatever a high-level moss
program looked like into machine instructions that were executed on the moss
processor.
That being said, there is nothing stopping me from building out a fully
integrated end-to-end moss
stack, even if other toolchains could also be used
to target the hardware. In other words, there is no reason to break basic
interoperability if we don’t gain anything from doing so.
RISC-V Non-Standard Extensions Link to heading
The foundational core of any instruction set looks mostly the same: arithmetic
operations, control flow, and memory access. The simplest RISC-V implementation
is one that only supports the base Integer (I
) extension (i.e. RV32I
,
RV64I
, RV128I
). On top of that base, there are a number of standard
extensions, such as Multiplication and Division (M
), Atomics (A
),
Single-Precision Floating Point (F
), and more. These extensions can be
combined to define new
profiles.
However, RISC-V also supports non-standard extensions, and though there are some parameters for implementation, they mostly allow for arbitrary new functionality to be implemented. From the unprivileged RISC-V specification:
A non-standard extension may be highly specialized and may conflict with other standard or non-standard extensions. We anticipate a wide variety of non-standard extensions will be developed over time, with some eventually being promoted to standard extensions.
This optionality frequently comes up as a critique of RISC-V as it could lead to
a complex fragmented ecosystem. However, for the purposes of moss
, it allows
me to choose to use RISC-V as the foundation for the processor without
restricting any further experimentation or customization that may be desired in
the future.
In fact, most of the compelling reasons for designing a new ISA could similarly
be achieved by designing a non-standard RISC-V extension, all while going
through a process that would translate more directly to work outside of the
moss
ecosystem.
Next Steps Link to heading
A nice side-effect of adopting RISC-V is that it makes immediate next steps more
clear: implementing an RV64I
core. Let’s get to it!