The program is based on the RISC-V architecture and uses open-source tools to teach people about VLSI chip design and RISC-V. The instructor for this internship is Kunal Ghosh Sir.
Name: Maaz Mahmood Siddique
College: KIET Group of Institutions
Email ID: [email protected]
GitHub Profile: maazm007
LinkedIN Profile: maazm-ece-vlsi
Task 1: Task is to install all the essential tools required for this internship such as Ubuntu on VMBox, GNU Toolchain, GTKWave, Yosys and iVerilog simulator
1. Install Ubuntu 20.04 LTS on Oracle Virtual Machine Box
2. Install RISC-V GNU ToolChain
The RISC-V GNU Compiler Toolchain is a free and open source cross-compiler for C and C++. It supports two build modes: Generic ELF/Newlib and Linux-ELF/glibc. The toolchain can be used to create assembly instructions and sequences for execution in a simulator and target FPGA
Use the following command to install GNU Toolchain
$ sudo apt install git
$ git clone https://github.com/riscv/riscv-gnu-toolchain
$ sudo apt-get install autoconf automake autotools-dev curl python3 python3-pip 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
$ mkdir /opt/riscv
$ ./configure --prefix=/opt/riscv --with-arch=rv64i --with-abi=lp64 --enable-multilib
$ sudo make
Now add /opt/riscv/bin
to PATH
$ gedit ~/.bashrc
Add the line export PATH="$PATH:/opt/riscv/bin"
in the end of file and save it. After that run the following command:
$ source ~/.bashrc
3. Install Yosys Open SYnthesis Suite
Yosys, or Yosys Open SYnthesis Suite, is a free, open-source framework for Verilog RTL synthesis. It can be used to process almost any synthesizable Verilog-2005 design, and to convert Verilog to BLIF, EDIF, BTOR, SMT-LIB, and more. Yosys can be customized to perform any synthesis job by combining the existing passes (algorithms) using synthesis scripts and adding additional passes as needed by extending the yosys C++ code base
Use the following command to install Yosys
$ git clone https://github.com/YosysHQ/yosys.git
$ cd yosys
$ sudo apt install make //If make is not installed, make sure to install it first
$ sudo apt-get install build-essential clang bison flex \
libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev
$ make config-gcc
$ make
$ sudo make install
4. Install GTKwave
waveform viewer
GTKWave is a free, lightweight waveform viewer that's used to display simulation output. It's based on the GTK library and supports VCD and LXT formats for signal dumps. A waveform viewer that allows for the visualization of simulation outputs, facilitating the analysis of digital signals.
Use the following command to install GTKWave
$ sudo apt update
$ sudo apt install gtkwave
5. Install Icarus Verilog
open source tool for simulation
Icarus Verilog is a compiler for the Verilog hardware description language (HDL). It's used to collect Verilog source code, check for errors, and write compiled design files. It also helps access source files in libraries, link modules, and write compiled results
Use the following command to install Icarus Verilog
$ sudo apt-get install iverilog
Task 2: Task is to identify instruction type of all the given instructions with its exact 32 bits instruction code in the desired instruction type format
- RISC-V is an open-source instruction set architecture (ISA) that allows developers to develop processors for specific applications.
- RISC-V is based on reduced instruction set computer principles and is the fifth generation of processors built on this concept.
- RISC-V can also be understood as an alternative processor technology which is free and open, meaning that it does not require you to purchase the license of RISC-V to use it.
The instructions format of a processor is the way in which machine language instructions are structured and organized for a processor to execute. It is made up of series of 0s and 1s, each containing information about the location and operation of data.
There are 6 instruction formats in RISC-V:
- R-format
- I-format
- S-format
- B-format
- U-format
- J-format
Let’s discuss each of the instruction formats in detail with examples.
In RV32, each instruction is of size 32 bits. In R-type instruction, R stands for register which means that operations are carried on the Registers and not on memory location. This instruction type is used to execute various arithmetic and logical operations. The entire 32 bits instruction is divided into 6 fields as shown below.
- The first field in the instruction format is known as opcode, also referred as operation code. The opcode is of length 7 bits and is used to determine the type of instruction format.
- The next subfield is known as rd field which is referred as Destination Register. The rd field is of length 5 bits and is used to store the final result of operation.
- The next subfield is func3 also referred as function 3. Here the ‘3’ represents the size of this field. This field tells the detail about the operation, i.e., the type of arithmetic and logical that is performed.
- The next two subfields are the source registers, rs1 and rs2 each of length 5 bits. These are mainly used to store and manipulate the data during the execution of instructions.
- The last subfield is func7 also referred as function 7. Here ‘7’ represents the size of the field. The function of func7 field is same as that of func3 field.
In RV32, each instruction is of size 32 bits. In I-type instruction, I stand for immediate which means that operations use Registers and Immediate value for their execution and are not related with memory location. This instruction type is used in immediate and load operations. The entire 32 bits instruction is divided into 5 fields as shown below.
- The first field in the instruction format is known as opcode, also referred as operation code. The opcode is of length 7 bits and is used to determine the type of instruction format.
- The next subfield is known as rd field which is referred as Destination Register. The rd field is of length 5 bits and is used to store the final result of operation.
- The next subfield is func3 also referred as function 3. Here the ‘3’ represents the size of this field. This field tells the detail about the operation, i.e., the type of arithmetic and logical that is performed.
- The next subfield is the source registers, rs1 of length 5 bits. It is mainly used to store and manipulate the data during the execution of instructions.
- The only difference between R-type and I-type is rs2 and func7 field of R-type has been replaced by 12-bits signed immediate, imm[11:0].
In RV32, each instruction is of size 32 bits. In S-type instruction, S stand for store which means it is store type instruction that helps to store the value of register into the memory. Mainly, this instruction type is used for store operations. The entire 32 bits instruction is divided into 6 fields as shown below.
- The first field in the instruction format is known as opcode, also referred as operation code. The opcode is of length 7 bits and is used to determine the type of instruction format.
- S-type instructions encode a 12-bit signed immediate, with the top seven bits imm[11:5] in bits [31:25] of the instruction and the lower five bits imm[4:0] in bits [11:7] of the instruction.
- S-type instruction doesn’t have rd fields which states that these instructions are not used to write value to a register, but to write/store a value to a memory.
- The value to be stored is defined in rs1 field and address to which we have to store this value is calculated using rs1 and immediate field. The width of the operation and types of instruction is defined by func3, it can be a word, half-word or byte.
In RV32, each instruction is of size 32 bits. In B-type instruction, B stand for branching which means it is mainly used for branching based on certain conditions. The entire 32 bits instruction is divided into 8 fields as shown below.
- The first field in the instruction format is known as opcode, also referred as operation code. The opcode is of length 7 bits and is used to determine the type of instruction format.
- B-type instructions encode a 12-bit signed immediate, with the most significant bit imm[12] in bit [31] of the instruction, six bits imm[10:5] in bits [25:30] of the instruction, four bits imm[4:1] in bits [11:8] and one bit imm[11] on bit[7].
- There are two source registers rs1 and rs2 on which various operations are performed based on certain conditions, and those conditions are defined by func3 field.
- After performing operations on the source register based on the conditions, it is evaluated that if the condition is true, Program Counter value gets updated by
PC = Present PC Value + Immediate Value
, and if the condition is false then PC will be given asPC = Present PC value + 4 bytes
, which states that PC will move to next instruction set. - RV32 instructions are word-aligned, which means that address is always defined in the multiple of 4 bytes.
In RV32, each instruction is of size 32 bits. In U-type instruction, U stand for Upper Immediate instructions which means it is simply used to transfer the immediate data into the destination register. The entire 32 bits instruction is divided into 3 fields as shown below.
- The first field in the instruction format is known as opcode, also referred as operation code. The opcode is of length 7 bits and is used to determine the type of instruction format.
- The U-type instruction only consists of two instructions, i.e.,
LUI
andAUIPC
. - For Example, lets take the instruction lui rd, imm and understand this instruction.
lui x15, 0x13579
: This instruction will be executed and the immediate value 0x13579 will be written in the MSB of the rd x15, and it will look like x15 = 0x13579000.
In RV32, each instruction is of size 32 bits. In U-type instruction, J stand for jump, which means that this instruction format is used to implement jump type instruction. The entire 32 bits instruction is divided into 6 fields as shown below.
- The first field in the instruction format is known as opcode, also referred as operation code. The opcode is of length 7 bits and is used to determine the type of instruction format.
- The J-type instruction only consists of single instruction,
JAL
. - J-type instruction encode 20 bits signed immediate which is divided into four fields.
- The J-type instructions are often used to perform jump to the desired memory location. The address of the desired memory location is defined in the instruction. These instructions are also used to implement loops.
ADD r6, r2, r1
- All the arithmetic and logical operations are performed using R-type instruction format, hence this instruction belongs to R-type instruction set.
- r6 is the destination register that will hold the sum of values stored in the register r2 and r1.
- Opcode for ADD = 0110011
rd = r6 = 00110
rs1 = r2 = 00010
rs2 = r1 = 00001
func3 = 000
func7 = 0000000
32 bits instruction : 0000000_00001_00010_000_00110_0110011
SUB r7, r1, r2
- All the arithmetic and logical operations are performed using R-type instruction format, hence this instruction belongs to R-type instruction set.
- r7 is the destination register that will hold the difference of values stored in the register r1 and r2.
- Opcode for SUB = 0110011
rd = r7 = 00111
rs1 = r1 = 00001
rs2 = r2 = 00010
func3 = 000
func7 = 0100000
32 bits instruction : 0100000_00010_00001_000_00111_0110011
AND r8, r1, r3
- All the arithmetic and logical operations are performed using R-type instruction format, hence this instruction belongs to R-type instruction set.
- r8 is the destination register that will hold the value of r1 & r3, means performing AND operation bit by bit.
- Opcode for AND = 0110011
rd = r8 = 01000
rs1 = r1 = 00001
rs2 = r3 = 00011
func3 = 111
func7 = 0000000
32 bits instruction : 0000000_00011_00001_111_01000_0110011
OR r9, r2, r5
- All the arithmetic and logical operations are performed using R-type instruction format, hence this instruction belongs to R-type instruction set.
- r9 is the destination register that will hold the value of r2 | r5, means performing OR operation bit by bit.
- Opcode for OR = 0110011
rd = r9 = 01001
rs1 = r2 = 00010
rs2 = r5 = 00101
func3 = 110
func7 = 0000000
32 bits instruction : 0000000_00101_00010_110_01001_0110011
XOR r10, r1, r4
- All the arithmetic and logical operations are performed using R-type instruction format, hence this instruction belongs to R-type instruction set.
- r10 is the destination register that will hold the value of r1 ^ r4, means performing XOR operation bit by bit.
- Opcode for XOR = 0110011
rd = r10 = 01010
rs1 = r1 = 00001
rs2 = r4 = 00100
func3 = 100
func7 = 0000000
32 bits instruction : 0000000_00100_00001_100_01010_0110011
SLT r11, r2, r4
- Since the logical operation is performed on registers, hence this instruction belongs to R-type instruction set.
- r1 is the destination register that sets to 1, if r2 is less than r4, else 0 if r2 is greater than r4.
- Opcode for SLT = 0110011
rd = r1 = 01011
rs1 = r2 = 00010
rs2 = r4 = 00100
func3 = 010
func7 = 0000000
32 bits instruction : 0000000_00100_00010_010_01011_0110011
ADDI r12, r4, 5
- In this instruction ADD means Addition, I means Immediate, therefore ADDI means Addition with Immediate, hence this instruction belongs to I-type instruction set.
- r12 is the destination register that will store the value of r5 sum-up with the immediate value 5.
- Opcode for ADDI = 0010011
rd = r12 = 01100
rs1 = r4 = 00100
imm[11:0] = 5 = 000000000101
func3 = 000
32 bits instruction : 000000000101_00100_000_01100_0010011
SW r3, r1, 2
- In this instruction SW means store word, hence this instruction belongs to S-type instruction set.
- r3 is the source register. This instruction will store the value located in register r3 at the address obtained by adding the immediate address 2 with the address located in register r1.
- Opcode for SW = 0100011
rs2 = r3 = 00011
rs1 = r1 = 00001
imm[11:0] = 2 = 000000000010
func3 = 010
32 bits instruction : 0000000_00011_00001_010_00010_0100011
SRL r16, r14, r2
- SRL means Logical Shift Right and since the operation is performed on registers, this instruction belongs to R-type instruction set.
- r16 is the destination register, in which the value stored in r14 will be written after performing logical right shift based on the number stored in r2.
- Opcode for SRL = 0110011
rd = r16 = 10000
rs1 = r14 = 01110
rs2 = r2 = 00010
func3 = 101
func7 = 0000000
32 bits instruction : 0000000_00010_01110_101_10000_0110011
BNE r0, r1, 20
- BNE is a branching instruction (B-type) based on conditions. Here BNE specifies the condition that the value stored in r0 != (is not equal to) the value stored in r1. If the condition becomes true, Program Counter will be updated by PC + 20, else PC + 4 for next instruction.
- Opcode for BNE = 1100011
rs1 = r0 = 00000
rs2 = r1 = 00001
imm[12:1] = 20 = 000000010100
func3 = 001
32 bits instruction : 0_000001_00001_00000_001_0100_0_1100011
BEQ r0, r0, 15
- BEQ is a branching instruction (B-type) based on conditions. Here BEQ specifies the condition that the value stored in r0 == (is equal to) the value stored in r0. If the condition becomes true, Program Counter will be updated by PC + 15, else PC + 4 for next instruction.
- Opcode for BEQ = 1100011
rs1 = r0 = 00000
rs2 = r0 = 00000
Imm[12:1] = 000000001111
func3 = 000
32 bits instruction : 0_000000_00000_00000_000_1111_0_1100011
LW r13, r1, 2
- LW stands for Load Word. Word is equal to 32 bits or 4 bytes. Since there is an immediate value given in the instruction which helps to calculate the address of memory from where we have to fetch the data, hence this instruction belongs to I-type.
- r13 is the destination register that will hold the value fetched from the memory location calculated by using (address value stored in r1 + immediate value)
- Opcode for LW = 0000011
rd = r13 = 01101
rs1 = r1 = 00001
imm[11:0] = 000000000010
func3 = 010
32 bits instruction : 000000000010_00001_010_01101_0000011
SLL r15, r1, r2
- SLL means Logical Shift Left and since the operation is performed on registers, this instruction belongs to R-type instruction set.
- r15 is the destination register, in which the value stored in r1 will be written after performing logical left shift based on the number stored in r2.
- Opcode for SLL = 0110011
rd = r15 = 01111
rs1 = r1 = 00001
rs2 = r2 = 00010
func3 = 001
func7 = 0000000
32 bits instruction :0000000_00010_00001_001_01111_0110011
Task 3: Task is to refer to C based and RISCV based lab videos and execute the task of compiling the C code using gcc and riscv compiler
We have to follow the given steps to compile any .c file in our machine:
-
Open the bash terminal and locate to the directory where you want to create your file. Then run the following command:
gedit sum_1ton.c
-
This will open the editor and allows you to write into the file that you have created. You have to write the C code of printing the sum of n numbers. Once you are done with your code, press
Ctrl + S
to save your file, and then pressCtrl + W
to close the editor. -
To the C code on your terminal, run the following command:
gcc sum_1ton.c ./a.out
We have to do the same compilation of our code but this time using RISCV gcc compiler. Follow the given steps:
-
Open the terminal and run the given command:
cat sum_1ton.c
-
Using the cat command, the entire C code will be displayed on the terminal. Now run the following command to compile the code in riscv64 gcc compiler:
riscv64-unknown-elf-gcc -O1 -mabi=lp64 -march=rv64i -o sum_1ton.o sum_1ton.c
-
Open a new terminal and run the given command:
riscv64-unknown-elf-objdump -d sum_1ton.o
- The Assembly Language code of our C code will be displayed on the terminal. Type
/main
to locate the main section of our code.
- -mabi=lp64: This option specifies the ABI (Application Binary Interface) to use
lp64
, which is for 64-bit integer, long and pointer size. This ABI is used for 64-bit RISCV architecture. - -march=rv64i: This option specifies the architecture that we use, which is rv64i, indicates the 64-bit RISCV base integer instruction set. This also confirms the targeting of 64-bit architecture.
- riscv-objdump: A tool for disassembling RISC-V binaries, providing insights into the code structure and helping in debugging.
- -Ofast: The option -Ofast in the command
riscv64-unknown-elf-gcc -Ofast -mabi=lp64 -march=rv64i -o sum1ton.o sum1ton.c
is a compiler optimization flag used with the GNU Compiler Collection (GCC). This flag is used to instruct the compiler to optimize the generated code for maximum speed. The use of-Ofast
is typically chosen for applications where execution speed is critical and where deviations from standard behavior are acceptable. However, it's important to test thoroughly, as this level of optimization can introduce subtle bugs, especially in complex calculations or when strict compliance with external standards is required. - -O1: This options is an optimization level that tells the compiler to optimize the generated code but without greatly increasing compilation time. -O1 aims to reduce code size and execution time while keeping the compilation process relatively quick.
- -O0: No optimization, the default level if no -O option is specified.
- -O2: More aggressive optimizations that might increase compilation time but typically provide faster and sometimes smaller code.
- -O3: Maximizes optimization more aggressively than -O2.
- -Os: Optimizes code for size. It enables all -O2 optimizations that do not typically increase code size.
Here, the term more aggressive optimization in the context of compilers like GCC refers to a deeper and more complex set of transformations applied to the code in order to improve its performance and possibly reduce its size. The compiler uses more complex techniques that aims to generate faster executing code or code that occupies less memory. However, these optimizations typically increase the compilation time and can sometimes introduce bugs, making it harder to debug.
Task 4: Performing SPIKE Simulation and Debugging the C code with Interactive Debugging Mode using Spike
- A RISC-V ISA is a simulator, enabling the testing and analysis of RISC-V programs without the need for actual hardware.
- Spike is a free, open-source C++ simulator for the RISC-V ISA that models a RISC-V core and cache system. It can be used to run programs and a Linux kernel, and can be a starting point for running software on a RISC-V target.
Use the following command to install SPIKE in your machine
$ git clone https://github.com/riscv/riscv-isa-sim.git
$ cd riscv-isa-sim
$ mkdir build
$ cd build
$ sudo apt-get install device-tree-compiler // to install the missing dependencies
$ sudo apt-get install libboost-all-dev // to install the libboost library
$ ../configure --prefix=/opt/riscv
$ make
$ sudo make install
$ sudo apt update
$ sudo apt install g++-8
$ make CXX=g++-8
$ echo 'export PATH=$PATH:/opt/riscv/bin' >> ~/.bashrc
$ source ~/.bashrc
- The RISC-V Proxy Kernel, pk , is a lightweight application execution environment that can host statically-linked RISC-V ELF binaries.
- A Proxy Kernel in the RISC-V ecosystem simplifies the interaction between complex hardware and the software running on it, making it easier to manage, test, and develop software and hardware projects.
Use the following command to install pk in your machine
Make sure you are on home directory
$ git clone https://github.com/riscv/riscv-pk.git
$ cd riscv-pk
$ mkdir build
$ cd build
$ ../configure --prefix=/opt/riscv --host=riscv64-unknown-elf --with-arch=rv64gc
$ make
$ sudo make install
The target is to run the sum_1ton.c
code using both gcc compiler
and riscv compiler
, and both of the compiler must display the same output on the terminal. So to compile the code using gcc compiler, use the following command:
gcc sum_1ton.c
./a.out
And to compile the code using riscv compiler, use the following command:
spike pk sum_1ton.o
RISCV Objdump with -O1 option
RISCV Objdump with -Ofast option
- Open the Objdump of code by using the following command
$ riscv64-unknown-elf-objdump -d sum_1ton.o | less
- Open the debugger in another terminal by using the following command
$ spike -d pk sum_1ton.o
- The debugger will be opened in the terminal. Now, debugging operations can be performed as shown in the following snapshot.
Task 5: By making use of RISCV Core: Verilog Netlist and Testbench, perform an experiment of Functional Simulation and observe the waveforms
NOTE: Since the designing of RISCV Architecture and writing it's testbench is not the part of this Research Internship, so we will use the Verilog Code and Testbench of RISCV that has already been designed. The reference GitHub repository is : iiitb_rv32i
-
Create a new directory with your name
mkdir <your_name>
-
Create two files by using
touch
command asmaazm_rv32i.v
andmaazm_rv32i_tb.v
-
Copy the code from the reference github repo and paste it in your verilog and testbench files
-
To run and simulate the verilog code, enter the following command:
$ iverilog -o maazm_rv32i maazm_rv32i.v maazm_rv32i_tb.v $ ./maazm_rv32i
-
To see the simulation waveform in GTKWave, enter the following command:
$ gtkwave maazm_rv32i.vcd
-
The GTKWave will be opened and following window will be appeared
As shown in the figure below, all the instructions in the given verilog file is hard-coded. Hard-coded means that instead of following the RISCV specifications bit pattern, the designer has hard-coded each instructions based on their own pattern. Hence the 32-bits instruction that we generated in Task-2 will not match with the given instruction.
Following are the differences between standard RISCV ISA and the Instruction Set given in the reference repository:
Operation | Standard RISCV ISA | Hardcoded ISA |
---|---|---|
ADD R6, R2, R1 | 32'h00110333 | 32'h02208300 |
SUB R7, R1, R2 | 32'h402083b3 | 32'h02209380 |
AND R8, R1, R3 | 32'h0030f433 | 32'h0230a400 |
OR R9, R2, R5 | 32'h005164b3 | 32'h02513480 |
XOR R10, R1, R4 | 32'h0040c533 | 32'h0240c500 |
SLT R1, R2, R4 | 32'h0045a0b3 | 32'h02415580 |
ADDI R12, R4, 5 | 32'h004120b3 | 32'h00520600 |
BEQ R0, R0, 15 | 32'h00000f63 | 32'h00f00002 |
SW R3, R1, 2 | 32'h0030a123 | 32'h00209181 |
LW R13, R1, 2 | 32'h0020a683 | 32'h00208681 |
SRL R16, R14, R2 | 32'h0030a123 | 32'h00271803 |
SLL R15, R1, R2 | 32'h002097b3 | 32'h00208783 |
Instruction 1: ADD R6, R2, R1
Instruction 2: SUB R7, R1, R2
Instruction 3: AND R8, R1, R3
Instruction 4: OR R9, R2, R5
Instruction 5: XOR R10, R1, R4
Instruction 6: SLT R1, R2, R4
Instruction 7: ADDI R12, R4, 5
Instruction 8: BEQ R0, R0, 15
Instruction 9: BNE R0, R1, 20
Instruction 10: SLL R15, R1, R2
Task 6: Final Task of this internship is to implement any digital circuits using VSDSquadron Mini and check whether the building and uploading of C program file on RISCV processor works
This project involves the implementation of Full Adder combinational circuit using VSDSquadron Mini, a RISCV based SoC development kit. Full Adder is a very important circuit in digital electronics, widely used in creating the design of n-bits Adder circuit. A full adder circuit is a digital circuit that adds two binary digits and a carry-in digit to produce a sum and carry-out digit. It's a central component of most digital circuits that perform addition or subtraction. This project demonstrates the practical application of digital logic and RISC-V architecture in executing arithmetic operation, reflecting the process of reading and writing of binary data through GPIO pins, implementing the operation of full adder through digital logic gates which is simulated using PlatformIO IDE and thus displaying the outputs using LEDs.
- VSDSquadron Mini
- Push Buttons for Input of binary data
- 2 LEDs for displaying the Output
- Breadboard
- Jumper Wires
- VS Code for Software Development
- PlatformIO multi framework professional IDE
- Input: Three input of single bit are connected to the GPIO pins of VSDSquadron Mini via push buttons mounted on the breadboard.
- Outputs: Two LEDs are connected to display the result of Full Adder
- The GPIO pins are configured according to the Reference Mannual, ensuring the correct flow of signals between the components
A | B | Cin | Sum | Carry |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
// Full Adder Implementation
// Included the requried header files
#include<stdio.h>
#include<debug.h>
#include<ch32v00x.h>
// Defining the Logic Gate Function
int and(int bit1, int bit2)
{
int out = bit1 & bit2;
return out;
}
int or(int bit1, int bit2)
{
int out = bit1 | bit2;
return out;
}
int xor(int bit1, int bit2)
{
int out = bit1 ^ bit2;
return out;
}
// Configuring GPIO Pins
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0}; // structure variable used for GPIO configuration
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); // to enable the clock for port D
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // to enable the clock for port C
// Input Pins Configuration
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // Defined as Input Type
GPIO_Init(GPIOD, &GPIO_InitStructure);
//Output Pins Configuration
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // Defined Output Type
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // Defined Speed
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
// The MAIN function responsible for the execution of program
int main()
{
uint8_t A, B, Cin, Sum, Carry; // Declared the required variables
uint8_t p, q, r, s, t;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SystemCoreClockUpdate();
Delay_Init();
GPIO_Config();
while(1)
{
A = GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_1);
B = GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_2);
Cin = GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3);
s = xor(A, B);
Sum = xor(Cin, s);
p = and(A, B);
q = and(B, Cin);
r = and(Cin, A);
t = or(p, q);
Carry = or(r, t);
/* SUM */
if(Sum == 0)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_4, SET);
}
else
{
GPIO_WriteBit(GPIOC, GPIO_Pin_4, RESET);
}
/* CARRY */
if(Carry == 0)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_5, SET);
}
else
{
GPIO_WriteBit(GPIOC, GPIO_Pin_5, RESET);
}
}
}
Acknowledgement
I would like to thank Kunal Ghosh Sir for this amazing internship experience on RISCV Architecture using VSDSquadron Mini. I was really passionate about diving into the world of RISCV, and here i got the kickstart. I had an amazing experience throughout this internship program. Thanks a lot VLSI System Design for launching such a phoenomenal research internship