Inside RISC-V microarchitecture

By: Valerii Haidarzhy, 10 Apr 2024
11 minutes

Reading Time: 11 minutes

If you’re intrigued by the world of open-source processor architectures, RISC-V is a game-changer that you won’t want to miss. This open standard instruction set architecture (ISA), offers a level of flexibility and customization that makes it an attractive option for various applications. Before diving into the inner workings of this revolutionary technology, we recommend checking out our comprehensive article that provides an overview of RISC-V and its benefits.

Understanding the main aspects of RISC-V is beneficial not only for developers and engineers but also for decision-makers evaluating different architectures for their projects and individuals seeking guidance in choosing a learning direction in the field. With a solid grasp of RISC-V, you’ll be well-equipped to make informed decisions and explore new opportunities in this innovative domain.

Memory hierarchy

RISC-V architecture defines a large, linear address space, which can be used for instructions, data, and stacks. The address space is 2^64 bytes long, providing a virtually unlimited amount of memory in case the needed extension is present. The linear address space simplifies programming and provides a uniform memory model that is independent of the underlying physical memory organization.

The instruction section contains the program code, and the data section contains the program’s data. The stack section is used to store temporary data, such as function call parameters, local variables, and return addresses. The stack grows downwards, while the heap grows upwards, which allows them to expand towards each other without colliding.

Cache design and levels:

RISC-V processors often employ cache memory to improve memory access performance. Cache memory stores frequently used data closer to the processor, reducing the time required to fetch data from the main memory. Cache memory is faster than main memory but smaller in size, so it can only store a portion of the data present in main memory.

Virtual memory and address translation:

RISC-V architecture, depending on extensions, can support the virtual memory, which allows each process to have its own virtual address space, isolated from others. Virtual memory enables multiple processes to share the same physical memory without interfering with each other’s address spaces. Virtual memory is divided into fixed-size blocks called pages, typically 4 KB in size.

The processor translates virtual addresses to physical addresses using a memory management unit (MMU) and a page table. The MMU is responsible for translating virtual addresses into physical addresses and providing memory protection, isolation, and efficient use of physical memory.

Pipeline

RISC-V pipeline architecture improves processing efficiency by breaking down instruction execution into five stages, enabling the simultaneous processing of multiple instructions. This approach decreases execution time and increases throughput. The five stages involve retrieving the instruction from memory, decoding the instruction, performing the specified operation, accessing memory for data transfer, and writing the results back to the register file.

The pipeline structure permits the processor to handle various instructions simultaneously, enhancing performance. However, this also presents challenges, such as pipeline hazards, which need to be addressed using methods like forwarding, stalling, and branch prediction to maintain efficiency and precision in execution.

Register file

The RISC-V register file consists of a set of registers used for holding data during instruction execution. The number of registers depends on the specific RISC-V variant being used.

RISC-V registers are named using a standard convention. For example, in the RV32I, there are 32 general-purpose registers named x0 to x31. The x0 register is hardwired to zero, while the others can be used for holding data.

In addition to general-purpose registers, RISC-V architecture includes special-purpose registers, such as the program counter (PC) and various control and status registers (CSRs). These registers control processor behavior and facilitate system-level functions like exception handling and virtual memory.

One of the most important special-purpose registers is the Program Counter (PC), which stores the address of the next instruction to be fetched from memory. During instruction execution, the PC is incremented to point to the next instruction in memory. When a branch or jump instruction is executed, the PC is updated to point to the new target address. Control and Status Registers (CSRs) are another type of special-purpose register used for controlling the processor’s behavior and reporting its status. CSRs are read and written using special instructions, providing access to control and status information such as interrupt status, privilege level, and trap handling.

ISA

Base instruction set

The base instruction set serves as the foundation of the RISC-V architecture. It defines a set of basic instructions for integer operations, control flow, and memory access.

The RISC-V ISA offers various base instruction set options to cater to a wide range of devices and applications. These base sets comprise fundamental instructions for memory access, control flow, and integer operations. The classification of these base sets is based on their data width, which dictates the maximum size of the data types and operands that can be handled.

Common instructions

The base integer instruction set of the RISC-V architecture includes a set of common instructions that are used for various operations. These instructions are categorized into different types based on their functionality.

Memory Access:

Memory access instructions are responsible for transferring data between the processor’s registers and memory. Key instructions in this category include

  • Load (Lx): These instructions read data from memory and store it in a register. Examples include Load Byte (LB), Load Halfword (LH), and Load Word (LW).
  • Store (Sx): These instructions write data from a register to memory. Examples include Store Byte (SB), Store Halfword (SH), and Store Word (SW).

Arithmetic and Logical Operations:

These instructions perform basic calculations and bitwise operations on data in registers. Some common instructions in this category are

  • Add (ADD): Adds the contents of two registers and stores the result in a destination register.
  • Subtract (SUB): Subtracts the contents of one register from another and stores the result in a destination register.
  • AND (AND): Performs a bitwise AND operation on the contents of two registers and stores the result in a destination register.
  • OR (OR): Performs a bitwise OR operation on the contents of two registers and stores the result in a destination register.
  • XOR (XOR): Performs a bitwise XOR operation on the contents of two registers and stores the result in a destination register.

Shift and Comparison Operations:

Shift and comparison instructions manipulate data in registers by shifting bits or comparing values. Examples of these instructions include

  • Shift Left Logical (SLL): Shifts the bits of a register value to the left by a specified number of positions, filling the vacated bits with zeros.
  • Shift Right Logical (SRL): Shifts the bits of a register value to the right by a specified number of positions, filling the vacated bits with zeros.
  • Shift Right Arithmetic (SRA): Shifts the bits of a register value to the right by a specified number of positions, preserving the sign bit.
  • Set Less Than (SLT): Compares two register values and sets the destination register to 1 if the first value is less than the second value, otherwise sets it to 0.

Control Flow:

Control flow instructions alter the flow of program executions by changing the program counter (PC). They include

  • Branch (Bx): These instructions allow for conditional branching based on register values. Examples include Branch if Equal (BEQ), Branch if Not Equal (BNE), Branch if Less Than (BLT), and Branch if Greater Than or Equal (BGE).
  • Jump and Link (JAL): This instruction jumps to a specified address and stores the return address in a register. It is used for function calls.
  • Jump and Link Register (JALR): Similar to JAL, this instruction jumps to an address specified in a register and stores the return address in another register. It supports indirect function calls.

Standard extensions

Extensions are optional modules that enhance the functionality of the base RISC-V instruction set. They provide additional features for specific application domains, such as floating-point arithmetic and vector processing.

Floating-point extensions

The floating-point extensions provide instructions for floating-point operations. These extensions are optional and can be added to any base instruction set option.

  • F extension:
    The F extension provides instructions for single-precision floating-point operations using 32-bit numbers. Examples of F extension instructions include FADD.S (floating-point addition), FSUB.S (floating-point subtraction), FMUL.S (floating-point multiplication), and FDIV.S (floating-point division).
  • D extension:
    The D extension contains instructions for double-precision floating-point operations using 64-bit numbers, like FADD.D (double-precision floating-point addition), FSUB.D (double-precision floating-point subtraction), FMUL.D (double-precision floating-point multiplication), and FDIV.D (double-precision floating-point division).
  • Q extension:
    The Q extension provides instructions for quad-precision floating-point operations using 128-bit numbers. For instance, FADD.Q (quad-precision floating-point addition), FSUB.Q (quad-precision floating-point subtraction), FMUL.Q (quad-precision floating-point multiplication), and FDIV.Q (quad-precision floating-point division).

Compressed instructions
The C extension provides compressed 16-bit instruction variants for common RISC-V instructions, reducing code size and improving energy efficiency. These compressed instructions have the same functionality as their standard counterparts but take up less memory space. Examples of C extension instructions include C.ADDI (compressed add immediate), C.MV (compressed move), and C.JR (compressed jump and link register).

Atomic operations
The Atomic Operations (A) extension of RISC-V architecture provides instructions that support atomic read-modify-write operations and load-reserved/store-conditional operations, which are useful for synchronization and parallelism in multiprocessor systems.

Vector instructions:
The Vector instructions (V) extension of RISC-V architecture defines a set of instructions that support Single Instruction, Multiple Data (SIMD) operations, which enable efficient parallel processing of data in applications such as machine learning, multimedia processing, and scientific computing.

The SIMD concept allows a single instruction to operate on multiple data elements simultaneously, which reduces the number of instructions needed to perform a given operation. For example, the VADD instruction can add multiple pairs of integer or floating-point numbers in a single instruction, instead of adding them one by one with individual instructions. Similarly, the VMUL instruction can perform multiple multiplications in parallel, and the VDOT instruction can perform a dot product operation on multiple pairs of vectors.

Bit manipulation
The B extension of RISC-V provides several instructions that support various bit manipulation operations, including bit counting, bit reversal, and bit-field manipulation. Below are some examples of these instructions:

Bit Counting:
Instructions such as Count Leading Zeros (CLZ), Count Trailing Zeros (CTZ), and Popcount (PCNT) allow the number of zeros and ones in a binary number to be counted. The CLZ instruction counts the number of leading zeros in a binary number, while the CTZ instruction counts the number of trailing zeros. The PCNT instruction counts the number of set bits (i.e., ones) in a binary number.

Bit Reversal:
The Reverse (REV) instruction reverses the order of bits in a register, which can be useful in certain algorithms and data manipulations. The instruction takes a 32-bit input and outputs a 32-bit output with its bits in reverse order.

Bit-Field Manipulation:
Instructions such as Bit Clear (BCLR), Bit Set (BSET), and Bit Field Place (BFP) allow for the extraction, modification, and insertion of bit fields within a register. These instructions are used to manipulate specific bits within a register without affecting the other bits. For example, the BCLR instruction clears a specific bit within a register, while the BSET instruction sets a specific bit within a register. The BFP instruction extracts a specific bit-field from a source register and inserts it into a destination register at a specific position.

Custom extensions

One of the key features of the RISC-V architecture is its extensibility, which allows developers to create custom extensions tailored to their specific needs. Custom extensions can be used to optimize performance, add specialized functionality, or differentiate a product in the market. They can also be employed to adapt RISC-V processors to specific application domains or safety-critical and fault-tolerant systems.

The RISC-V community provides guidelines and tools for designing and implementing custom extensions. Developers can create new instructions or modify existing ones to suit their requirements. 

RISC-V Software ecosystem

The RISC-V software ecosystem provides developers with the necessary tools, libraries, and operating systems to create and run software on RISC-V hardware. The ecosystem is continually evolving and expanding as the RISC-V community grows.

Toolchain

The RISC-V toolchain comprises a set of tools developers use to create, compile, and debug software for RISC-V processors. Some of the most popular tools in the RISC-V toolchain include:

  • GNU Compiler Collection (GCC):
    GCC is a popular open-source compiler that supports RISC-V. It provides support for compiling C, C++, and other languages to RISC-V assembly and machine code. GCC is widely used in the RISC-V ecosystem due to its performance and broad language support.
  • LLVM:
    LLVM is another open-source compiler infrastructure that supports RISC-V. It offers a modern, modular, and extensible design that allows for easier integration with other tools and languages. LLVM has been gaining popularity in the RISC-V ecosystem, especially for projects that require more advanced optimization and code generation features.
  • Binutils:
    Binutils is a collection of binary tools, including assembler, linker, and other utilities, that support RISC-V. These tools are essential for creating executable binaries and libraries for RISC-V platforms.
  • Debugging tools:
    Debugging tools, such as GDB (GNU Debugger), are used for identifying and fixing software issues. GDB supports RISC-V and allows developers to debug their code on RISC-V hardware or simulators.

Operating systems

Several operating systems support RISC-V, providing developers with a variety of options depending on their project requirements. Some of the most notable include:

  • Linux:
    The Linux kernel has added support for RISC-V, enabling developers to run Linux-based distributions like Debian and Fedora on RISC-V hardware. This support allows for a wide range of applications, from embedded systems to servers and workstations, to benefit from the RISC-V architecture.
  • FreeBSD:
    A popular open-source Unix-like operating system has also added support for RISC-V. FreeBSD provides a reliable and high-performance platform for RISC-V systems, particularly in networking and storage applications, with ports such as RISC-V FreeBSD and FreeBSD/RISC-V64.
  • Zephyr:
    Small, scalable, real-time operating system (RTOS) designed for use in resource-constrained environments. It supports RISC-V and is an excellent choice for embedded systems and IoT devices that require a lightweight and customizable OS, with builds like Zephyr RISC-V HiFive1 and Zephyr RISC-V Litex.

Several other real-time operating systems support RISC-V, such as FreeRTOS (RISC-V FreeRTOS SiFive and RISC-V FreeRTOS PULP), RIOT (RIOT RISC-V PicoRV32 and RIOT RISC-V VexRiscv), and NuttX (NuttX RISC-V GAP8 and NuttX RISC-V Kendryte K210). 

Application development

Developing applications for RISC-V platforms involves working with a wide array of software domains, from embedded systems and IoT devices to high-performance computing (HPC). To support these diverse needs, the RISC-V ecosystem offers a comprehensive selection of libraries and frameworks

  • Standard Libraries:
    Libraries like glibc and newlib provide the foundation for building C and C++ applications on RISC-V platforms. These standard libraries offer fundamental functions that are used for developing applications in these languages.
  • Numeric and Scientific Libraries:
    For high-performance linear algebra and signal processing applications, developers can leverage numeric and scientific libraries such as OpenBLAS, LAPACK, and FFTW. These libraries are specifically designed to optimize performance on RISC-V platforms and ensure that applications can efficiently handle complex mathematical operations.
  • Middleware and Communication Libraries:
    To create distributed and connected applications on RISC-V platforms, developers can utilize middleware and communication libraries such as MQTT, ZeroMQ, and DDS. These libraries simplify the process of creating applications that need to communicate across networks or between different components, making it easier to build sophisticated, interconnected systems.
  • Machine Learning and AI Frameworks:
    With the growing importance of AI in various domains, RISC-V supports machine learning and AI frameworks like TensorFlow Lite. By using these frameworks, developers can create AI-powered applications that take full advantage of the capabilities of RISC-V hardware.

Getting started with RISC-V development from scratch

Starting RISC-V development might seem challenging, but with the appropriate resources and guidance, you can confidently explore this fascinating domain. Let’s outline the primary steps.

  • Get a RISC-V development board: Begin your journey by obtaining a RISC-V evaluation board, such as the HiFive1 Rev B, Kendryte K210, or BeagleV. These boards offer an excellent foundation for learning and experimenting with development.
  • Set up your toolchain and IDE: Choose a RISC-V toolchain and integrated development environment (IDE) to streamline the development process. Toolchains line the GNU RISC-V Embedded GCC can be downloaded and installed for your convenience
  • Compile a simple program: Start with a simple program like “Hello World” to familiarize yourself with the RISC-V development environment. Gradually progress to more complex projects as you gain confidence.
  • Explore the RISC-V architecture:

Once you’ve gained some hands-on experience, proceed into the RISC-V architecture. The RISC-V ISA manual is a valuable resource for understanding when you feel ready and confident enough.

  • Learn RISC-V Assembly language: Gain insight into the low-level operations of RISC-V processors by studying assembly language programming. Utilize sample programs, online tutorials, and books to enhance your understanding.
  • Investigate operating systems and libraries: Expand your RISC-V development knowledge by exploring available operating systems and libraries, such as Linux, FreeBSD, Zephyr, glibc, newlib, TensorFlow Lite, and middleware libraries like MQTT and ZeroMQ.
  • Join the RISC-V Community: Engage with the RISC-V community through online forums, mailing lists, and social media platforms. Attend conferences and workshops to network with fellow RISC-V enthusiasts and industry professionals, sharing your experiences and learning from others.

Partnering with Sirin Software for RISC-V development

Embarking on RISC-V development might feel overwhelming, but don’t worry! If you ever find yourself stuck or need expert assistance, Sirin Software is here to help. Our experienced team can help you configure everything seamlessly for a smooth development experience. Want to dive deeper into RISC-V possibilities? We can always offer valuable resources and share our expertise in these areas. Our team completed SDK development for RISC-V, including basic FreeRTOS support, updates, and new functions like encryption acceleration.  By partnering with Sirin Software, you’re not just gaining technical assistance – you’re joining a supportive community of industry professionals. So, if you’re ready to take your RISC-V development to the next level or simply need a helping hand, Sirin Software is just a message away.  Reach out to us today, and let us become your trusted guide on this exciting journey.