Introduction
Welcome to the RiscY Documentation. In this documentation we will be talking on how to set up the RiscY project, and set it up for the TangNano9k and Primer25k FPGAs.
The RiscY project is a simple RISC-V processor that is designed to run on the TangNano9k FPGA. The RiscY processor is a 32-bit processor that is designed to run on the TangNano9k FPGA. The processor is designed to be simple and easy to understand, and is designed to be used as a learning tool for students who are interested in learning about computer architecture and digital design.
The Sipeed Tang Nano 9k FPGA and Primer 25k are small, low-cost FPGA boardss that can be used to implement digital designs. The boards are developed by Sipeed and can be had for the low cost of $20-$40.
Installation
You can start by downloading the source code from our Github
There are a total of 3 folders in the Github directory:
- RiscY: Contains the Verilog code for the RiscY processor along with the build. This folder also contains the Gowin EDA project file so you can build the project immidiately for the Tang Nano 9k
- RiscY Emulator: Contains an emulator of our RiscY system. It can run code at a max speed of 1MHz. The code is outdated since it does not include a button interface, flash or the cpu counters.
- riscYcompiler: Contains the software for the RiscY processor along with the important makefiles to compile the bootloader, applications and make an image for the Flash
Before you can build the project you will need to download the Gowin EDA from Gowin's website. You may also have a few problems with the drivers. You can find a fix for the drivers from Lushay.
Architecture
The CPU
The architecture of RiscY is based on the RISC-V architechure. It is a 32-bit processor that is designed to run on the TangNano9k FPGA. The processor has a 5-stage pipeline that is designed to be simple and easy to understand. For now the proccessor can run RV32I instructions only. The plan is to implement both the RV32-M for multiplication and divisions and the Ziscr extension for interrupts.
The Memory
The current memory layout contains 3 types of memories:
- Bootloader: This is a hardcoded memory that contains the bootloader code that we will be talking about in the Application Development Section. Its is mapped with registers and has a total size of 2KB. This is used to get the initial boot code, set up the runtime environment, get the files headers from the Flash and give the user the ability to select which program to run. It then copies the selected program from the flash to the RAM and jumps to the RAMP code location.
- RAM: A Random Access Memory that utilizes the FPGA's BRAMs in order to be able to run the copied program from the bootloader. With a total size of 8KB you are limited on what you can do with it. In the future we will implement the Hyper RAM from the Tang Nano 9k in order to have a bigger memory.
- Flash: In the flash we have the files that are burned with the help of our Program merger script. It has a total size of 4MB and is really slow. For context, to burn 1MB of data in it, you have to wait 1 hour
The Bus
The bus is a simple bus that is used to communicate between the CPU and the memories. It is a 32-bit bus that is used to read and write data from the memories. It is a combinational circuit that utilizes multiplexers to send the correct Read and Write enable signals to the correct modules and peripherals.
The Peripherals
The peripherals are the modules that are connected to the bus. They are the following:
- Buttons: The buttons are used to select the program that you want to run. They are connected to the bus and are read by the CPU.
- USB: USB HID Keyboard interface for easier interfacing with the CPU. They are connected to the bus and are read by the CPU.
- Screen: This is the main way that the cpu communicates with the outer world. It is memory mapped and due to the low amount of fast memory available only allows VGA Text Mode type of text.
- Clocks: These are simple 32 bit clock counters that are used in programs to be able to calculate time passed during the runtime.
Application Development
Bootloader
The bootloader is the first program that runs when the FPGA is powered on. It is a simple program that is used to set up the runtime environment, get the files headers from the Flash and give the user the ability to select which program to run. It then copies the selected program from the flash to the RAM and jumps to the RAMP code location.
Applications
Applications are the programs that are run by the RiscY processor. They are written in C and are compiled using the riscYcompiler. The applications are then burned to the flash using the Program merger script. The applications are then selected by the user using the buttons and are run by the RiscY processor.
Program Merger
The program merger is a simple script that is used to merge the applications into a single file that is burned to the flash. The script takes the applications and merges them into a single file that is burned to the flash. The script is written in Python and is run from the command line.
The compiler
For the compiler we utilize the RISCV gcc variant in order to cross-compile from our host machine to the RiscY system. In order to be able to use this, you are going to have to install it on your machine.
The installation varies for different systems. In order to be able to work on both the Gowin EDA you can use either Ubuntu or Windows with Ubuntu WSL2 for the compiler.
For Ubuntu you can install the compiler by running the following commands:
sudo apt install git
sudo apt install gawk
sudo apt install texinfo
sudo apt install bison
sudo apt install flex
sudo apt install zlib1g-dev
sudo apt install libgmp-dev libmpfr-dev libmpc-dev
git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
./configure --prefix=/opt/riscv --with-arch=rv32im --with-abi=ilp32
sudo make
# add this to your bash source
nano ~/.bashrc
export PATH=/opt/riscv/bin:$PATH
# save and exit
source ~/.bashrc
sudo apt-get install libftdi1-2 libftdi1-dev libhidapi-hidraw0 libhidapi-dev libudev-dev zlib1g-dev cmake pkg-config make g++
git clone https://github.com/trabucayre/openFPGALoader.git
cd openFPGALoader
mkdir build
cd build
cmake ../
cmake --build .
sudo make install
cd ..
sudo cp 99-openfpgaloader.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules && sudo udevadm trigger # force udev to take new rule
sudo usermod -a $USER -G plugdev # add user to plugdev group
# This should be done for the location where you built the openFPGALoader
nano ~/.bashrc
# add the following line
export PATH="$PATH:~/openFPGALoader/build"
source ~/.bashrc
PLEASE NOTE THIS TAKES AROUND 1 HOUR. Also some further libraries may be missing so please check the errors when using $sudo make
The riscYstdio.h
The riscYstdio.h is a simple library that is used to communicate with the I/O of the cpu. It contains some implementations of the gcc stdio.h library.
The functions that are implemented in the riscYstdio.h are the following:
void *memcpy(void *dest, const void *src, int n): This function is used to copy n bytes from the source to the destination. It is a simple recreation of the stdio.h memcopy(). It is needed for some optimizations of the compiler for .bss initiated items.void *memset(void *s, int c, size_t n)This function is used to set the default values of a chunk of memory. This is also a simple recreation of the stdio.h memset(). It is needed for some optimizations of the compiler for .bss uninitiated items.char getButton(char btn)This function returns the current value of the btn selected. The buttons are memory mapped and we will be talking on the memory mapped section. It returns true if the button is pressed and 0/false if it is not pressed.unsigned char putch(int location, char c, char color): This function is used to print a character to the screen. Recreation of the putch of stdio but takes an input the location of the character to be printed and the color based on the VGA Text mode. Returns 1 if the write was successfull or 0 if it wasn't.unsigned int printString(int location, char *string, char color): This function is used to print a string at the location with the color given as an argument. Doesn not support \n (new line) characters. The color is based on the VGA Text mode. Returns the number of characters printed.unsigned char printHex(int location, int value, char color): This function prints an 32 bit item as a hexadecimal at the location and the color specified by the user. The color is based on the VGA Text mode. Mostly used for the printf() function. Returns the number of characters printed.unsigned char printDec(int location, unsigned int num, char color): This function prints a positive integer less than 10.000 at the specified location and color. The color is based on the VGA Text mode. Mostly used for the printf() function. The small size of integer is due to the missing division extension, making it really slow for bigger numbers. Returns the number of characters printed.int printf(const char* str, ...): This function is a recreation of the stdio.h printf(). Takes a string and arguments and parses it to display the selected text. It keeps track of the current position of the printed strings. It can handle hex decimals, characters, strings and new lines. Returns the final position of the text.void resetScreenVector(): Resets the printf() character tracker in order to be able to write at the start of the screen again.int printfSCR(int location, char color, const char* str, ...): Works the same as the printf() with the only difference being that you explicitly set the position and color as arguments. Returns the number of characters printed.void clearScreen(): Simply clears the screen with blank characters.
Credits
- Panagiotis Nanousis
- Iordana Gaisidou
- Konstantinos Varakliotis
- Dimitrios Voitsidis