
Introduction to RISC-V
An Instruction Set Architecture (ISA) is an abstract model of a computer that defines how software controls the hardware. It specifies:
The set of instructions the processor can execute.
The data types it can operate on.
The registers are available.
How memory is accessed.
The interrupt handling mechanisms.
RISC-V Philosophy and RV32I's Role: RISC-V (Reduced Instruction Set Computer - Five) is an open-source ISA. Unlike proprietary ISAs (like x86 or ARM), anyone can use, modify, and distribute RISC-V designs without licensing fees. This open nature fosters innovation and customization.
RV32I is the 32-bit base integer instruction set. It's the most basic and mandatory part of any RISC-V implementation. It was designed to be:
Simple: It has a small, streamlined set of instructions (around 40 unique instructions), making it easier to design and implement hardware.
Efficient: Its fixed-width 32-bit instructions and consistent format simplify decoding and lead to faster execution.
Compiler Target: It's sufficient to serve as a target for compilers, allowing for C/C++ programs to be compiled and run on RV32I processors.
Minimal Hardware: Designed to reduce the hardware required for a basic implementation, making it suitable for resource-constrained environments.
In the RV32I instruction set, "Register-type" instructions (often called R-type instructions) are a fundamental category for operations that primarily involve values stored in registers. These instructions perform arithmetic and logical computations using two source registers and write the result to a destination register.
The "I-type" instruction format in RV32I is a crucial category used for operations that involve a register and an immediate (constant) value, as well as for load instructions and the JALR (Jump and Link Register) instruction.
Here's a detailed explanation of I-type instructions in RV32I:
1. Purpose: I-type instructions serve several key purposes in RV32I:
Immediate Arithmetic/Logical Operations: Performing arithmetic or bitwise logical operations between a source register and a small, signed immediate value.
Load Instructions: Loading data from memory into a register. The immediate value is used as an offset from a base address in a register.
Jump and Link Register (JALR): Used for indirect jumps, often for function returns or switch statements.
A lab session to demonstrate how to write assembly code in Risc-V simulator and run it.
Verilog is a widely used Hardware Description Language (HDL) that enables engineers to model, design, and simulate digital electronic systems. Unlike traditional programming languages that execute sequentially, Verilog describes hardware that operates concurrently, meaning different parts of the circuit function in parallel, just like real-world electronics.
It allows designers to work at various levels of abstraction, from high-level behavioral descriptions (what the circuit does) to detailed gate-level implementations (how it's physically built). This flexibility makes Verilog suitable for designing everything from simple logic gates to complex microprocessors and entire Systems-on-Chip (SoCs).
Verilog code is processed by synthesis tools that translate the high-level descriptions into actual physical gates and interconnections (a netlist), which can then be fabricated onto an Application-Specific Integrated Circuit (ASIC) or programmed onto a Field-Programmable Gate Array (FPGA). It's an indispensable tool in modern digital circuit design, bridging the gap between abstract design concepts and tangible hardware.
Modules and data types
Different operators available in Verilog
Why is Bit Extension Important?
Arithmetic Operations: When performing addition, subtraction, or multiplication on numbers of different bit widths, bit extension is crucial to ensure correct results. For instance, if you add an 8-bit signed number to a 16-bit signed number, the 8-bit number must be sign-extended to 16 bits before the addition.
Data Path Widening: Sometimes, you need to pass a smaller data value through a wider data path or store it in a larger register. Bit extension (either zero or sign, depending on whether the number is unsigned or signed) ensures the value is correctly represented.
Avoiding Truncation Errors: If you assign a wider number to a narrower wire or register, bits will be truncated (lost from the MSB side), potentially leading to incorrect values. Bit extension ensures you have enough bits to represent your values before operations that might widen them.
Example:
module SignExtension (
input [7:0] data_in_signed, // 8-bit signed input
output [15:0] data_out_signed // 16-bit output (sign-extended)
);
// Replicate the MSB (data_in_signed[7]) for the new higher bits
assign data_out_signed = {{8{data_in_signed[7]}}, data_in_signed};
endmodule
Here, {{8{data_in_signed[7]}}} creates an 8-bit vector by repeating data_in_signed[7] (the sign bit) 8 times. This ensures the sign is preserved.
In Verilog, numbers are a fundamental aspect of describing digital hardware. Unlike general-purpose programming languages, where numbers primarily represent abstract mathematical values, in Verilog, they often represent actual physical signals or values stored in hardware elements. This means their bit-width and base are critical.
In Verilog, initial and always blocks are the fundamental procedural blocks used to describe sequential and combinational logic behavior. They are key to behavioral modeling, allowing you to specify how values change over time or in response to events.
Verilog, as a Hardware Description Language (HDL), provides various modeling styles to describe digital circuits at different levels of abstraction. This flexibility allows designers to choose the most appropriate style for their needs, from high-level behavioral descriptions to detailed gate-level implementations.
Note: While installing Icarus Verilog, make sure that the PATH option is tick-marked. Otherwise, VS Code is unable to find it.
Hint: Dont change the default installation settings except installation directory(if required).
Copy the testbench inside the same directory where main module exist.
Place all these files inside a single directory
The installation and configuration of the RISC-V toolchain for compiling C programs is discussed. Note the following points carefully.
1. If you have a Linux PC (preferably Ubuntu) or Windows Subsystem for Linux (WSL), follow this step and the following commands to configure and install.
git clone https://github.com/riscv/riscv-gnu-toolchain
sudo apt-get install autoconf automake autotools-dev curl python3 python3-pip python3-tomli libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev ninja-build git cmake libglib2.0-dev libslirp-dev
cd riscv-gnu-toolchain
./configure --prefix=/opt/riscv --with-arch=rv32i --with-abi=ilp32
make linux
Note: --prefix is the preferred installation directory where the binaries will be stored after building the toolchain. It must have permission to rw access. For example: /home/charlie/riscv. Note that the whole steps require a long time to download the toolchain (several gb) and a long building time. For more details, refer to the official git repo of risc-v toolchain.
2. If you are a Windows user and not interested in using WSL, not configured, or unable to configure it, then follow this step.
Download pre-compiled binary (EXE file) for Windows from here (a little backdated version, but it works fine)
https://sysprogs.com/getfile/40/risc-v-gcc7.7.1.exe
Install it, and the required compiler will be installed. Although this is mainly for 64-bit but it also supports 32-bit with RV32I ISA.
Make sure that Python is installed on your system. Otherwise, hex file generation is not possible.
This lecture discusses the method to add LED GPIO. In the attached ZIP file, related Verilog files, testbench, and inside sw folder, the C code and associated files are present.
Check the sw folder given in previous attachment for related C code
Source files of LED gpio is attached. If you are using Gowin EDA, then click the blue colored icon (GPRJ file) to open the project directly. All source files are present inside src directory.
The UART Transmitter project source code for Tang-9K FPGA and the RISC-V GCC source code is attached. Navigate to the src folder to find the source code (.v files) and other config files.
UART Receiver project code and C source files are in the attachment.
In this lecture, the process of combining the LED, UART transmitter, and receiver is discussed. This makes a complete, fully-functional SoC using Verilog and an FPGA. Everything is designed from scratch and is working perfectly.
This comprehensive course, "Designing RISC-V CPU in Verilog and its FPGA Implementation", offers a deep dive into the fascinating world of custom processor design, focusing on the open-source RISC-V instruction set architecture (ISA). Participants will gain hands-on experience in architecting, describing, and implementing a functional RISC-V CPU core using the Verilog Hardware Description Language (HDL) and deploying it on Field-Programmable Gate Arrays (FPGAs).
The course begins by establishing a strong foundation in digital logic design principles and reviewing essential Verilog constructs relevant to complex digital systems. We will then introduce the RISC-V ISA (RV-32I), exploring its modularity, extensibility, and key instruction formats. Students will learn how to interpret the ISA specifications and translate them into hardware logic.
This course also provides step-by-step guidelines to set up the RISC-V toolchain, including assembler and GCC compiler, to write an embedded-C programme and compile it to Hex code, which will be loaded into an FPGA to access peripherals such as LEDs and UART.
A significant portion of the course is dedicated to the step-by-step design of a single-cycle RISC-V CPU. Topics covered will include:
Instruction Fetch Unit: Designing the program counter and instruction memory interface.
Decode Unit: Implementing instruction decoding logic, register file access, and control signal generation.
Execute Unit: Building the Arithmetic Logic Unit (ALU) and handling data path operations.
Memory Unit: Designing data memory interfaces for load and store operations.
Write-back Unit: Updating the register file with computed results.
Control Unit: Developing the finite state machine (FSM) or combinational logic to orchestrate CPU operations.
Emphasis will be placed on best practices in Verilog coding for synthesis, including modular design, parameterization, and robust test bench creation. Students will learn how to simulate their Verilog designs using industry-standard tools to verify functional correctness at each stage of the CPU development.
The latter part of the course focuses on the practical aspects of FPGA implementation. Participants will learn how to:
Synthesize their Verilog CPU design into a gate-level netlist.
Perform Place and Route to map the design onto specific FPGA resources.
Generate bitstreams for programming the FPGA.
Debug and test their implemented CPU on actual FPGA hardware, often by integrating peripherals like LEDs and UART for basic I/O and interaction.
By the end of this course, students will not only have a thorough understanding of RISC-V architecture and CPU design principles but also possess the practical skills to bring a complex digital design from concept to a working hardware implementation on an FPGA. This knowledge is invaluable for careers in embedded systems, custom silicon design, hardware acceleration, and research in computer architecture. A basic understanding of digital logic and Verilog is recommended.
Note: Only Base Integer Instruction (RV32I) is discussed and implemented in Verilog and FPGA. Also, you need one FPGA board for the hardware implementation of CPU. A basic FPGA board, such as Tang-9K, is sufficient for this.