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!