diff --git a/Makefile b/Makefile index d5840b3c..bd83b2db 100644 --- a/Makefile +++ b/Makefile @@ -61,11 +61,20 @@ Target = atombones VC = verilator VFLAGS = -cc -Wall --relative-includes --trace -D__ATOMSIM_SIMULATION__ +verilog_files = $(rtl_dir)/Timescale.vh +verilog_files += $(rtl_dir)/core/Utils.vh +verilog_files += $(rtl_dir)/core/Defs.vh +verilog_files += $(rtl_dir)/core/AtomRV.v +verilog_files += $(rtl_dir)/core/Alu.v +verilog_files += $(rtl_dir)/core/Decode.v +verilog_files += $(rtl_dir)/core/RegisterFile.v +verilog_files += $(rtl_dir)/core/CSR_Unit.v + # Target Specific definitions ifeq ($(Target), atombones) # ----- AtomBones ----- verilog_topmodule = AtomBones verilog_topmodule_file = $(rtl_dir)/$(verilog_topmodule).v -verilog_files = $(verilog_topmodule_file) $(rtl_dir)/Timescale.vh $(rtl_dir)/Config.vh $(rtl_dir)/core/AtomRV.v $(rtl_dir)/core/Alu.v $(rtl_dir)/core/Decode.v $(rtl_dir)/core/RegisterFile.v $(rtl_dir)/core/CSR_Unit.v +verilog_files += $(verilog_topmodule_file) sim_cpp_backend = $(sim_dir)/Backend_AtomBones.hpp CFLAGS += -DTARGET_ATOMBONES @@ -73,7 +82,17 @@ else ifeq ($(Target), hydrogensoc) # ----- HydrogenSoC ----- verilog_topmodule = HydrogenSoC verilog_topmodule_file = $(rtl_dir)/$(verilog_topmodule).v -verilog_files = $(verilog_topmodule_file) $(rtl_dir)/Timescale.vh $(rtl_dir)/Config.vh $(rtl_dir)/uncore/BiDirectionalIO.v $(rtl_dir)/uncore/GPIO.v $(rtl_dir)/uncore/DualPortRAM_wb.v $(rtl_dir)/uncore/SinglePortRAM_wb.v $(rtl_dir)/uncore/simpleuart_wb.v $(rtl_dir)/uncore/simpleuart.v $(rtl_dir)/core/AtomRV_wb.v $(rtl_dir)/core/AtomRV.v $(rtl_dir)/core/Alu.v $(rtl_dir)/core/Decode.v $(rtl_dir)/core/RegisterFile.v $(rtl_dir)/core/CSR_Unit.v + +verilog_files += $(rtl_dir)/core/AtomRV_wb.v +verilog_files += $(rtl_dir)/uncore/BiDirectionalIO.v +verilog_files += $(rtl_dir)/uncore/GPIO.v +verilog_files += $(rtl_dir)/uncore/DualPortRAM_wb.v +verilog_files += $(rtl_dir)/uncore/SinglePortRAM_wb.v +verilog_files += $(rtl_dir)/uncore/simpleuart_wb.v +verilog_files += $(rtl_dir)/uncore/simpleuart.v +verilog_files += $(rtl_dir)/HydrogenSoC_Config.vh +verilog_files += $(verilog_topmodule_file) + VFLAGS += -D__IMEM_INIT_FILE__='"$(RVATOM)/$(init_dir)/code.hex"' VFLAGS += -D__DMEM_INIT_FILE__='"$(RVATOM)/$(init_dir)/data.hex"' @@ -230,6 +249,7 @@ libs: $(build_dir) $(bin_dir) @echo "$(COLOR_GREEN)>> Compiling software libraries ...$(COLOR_NC)" cd sw/lib && make Target=$(Target) + # ======== Documentation ======== #~ docs : Generate atomsim C++ source documentation .PHONY: docs @@ -245,8 +265,6 @@ pdf-docs: docs $(doc_dir) $(doxygen_doc_dir) mv doc/doxygen/latex/refman.pdf doc/Atomsim_source_documentation.pdf - - # ======== clean ======== #~ clean : Clean atomsim build files .PHONY: clean diff --git a/boards/spartan6-mini/spartan6-mini.xise b/boards/spartan6-mini/spartan6-mini.xise index 367bffa7..6a69ca27 100644 --- a/boards/spartan6-mini/spartan6-mini.xise +++ b/boards/spartan6-mini/spartan6-mini.xise @@ -319,6 +319,7 @@ + @@ -359,11 +360,13 @@ - + + + diff --git a/install-toolchain.sh b/install-toolchain.sh index 2440750c..76f1bb15 100755 --- a/install-toolchain.sh +++ b/install-toolchain.sh @@ -7,7 +7,7 @@ TOOLCHAIN_CONFIG=--enable-multilib BUILD_JOBS=4 # Toolchain install root directory (Note: Toolchain will be installed inside a folder named TOOLCHAIN_NAME in the TOOLCHAIN_ROOTPATH) -TOOLCHAIN_ROOTPATH=/home/frozenalpha/opt/riscv +TOOLCHAIN_ROOTPATH=/home/${user}/opt/riscv ######################################################### # You sould not change anything below this diff --git a/rtl/AtomBones.v b/rtl/AtomBones.v index a8e74c4f..06ad5d4f 100644 --- a/rtl/AtomBones.v +++ b/rtl/AtomBones.v @@ -1,10 +1,18 @@ -/** - * Barebones Atom - */ +/////////////////////////////////////////////////////////////////// +// File : AtomBones.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : AtomBones is a wrapper for AtomRV_wb, it is a +// stub SoC target for AtomSim, which uses software simulated +// memories and communication modules. +/////////////////////////////////////////////////////////////////// + `include "Timescale.vh" -`include "Config.vh" +`include "AtomBones_Config.vh" + `include "core/AtomRV.v" +`default_nettype none + module AtomBones ( input wire clk_i, @@ -26,22 +34,22 @@ input wire dmem_ack_i // DMEM Ack signal ); -// Core -AtomRV atom_core -( - .clk_i (clk_i), - .rst_i (rst_i), - .imem_addr_o (imem_addr_o), - .imem_data_i (imem_data_i), - .imem_valid_o (imem_valid_o), - .imem_ack_i (imem_ack_i), - .dmem_addr_o (dmem_addr_o), - .dmem_data_i (dmem_data_i), - .dmem_data_o (dmem_data_o), - .dmem_sel_o (dmem_sel_o), - .dmem_we_o (dmem_we_o), - .dmem_valid_o (dmem_valid_o), - .dmem_ack_i (dmem_ack_i) -); + // Core + AtomRV atom_core + ( + .clk_i (clk_i), + .rst_i (rst_i), + .imem_addr_o (imem_addr_o), + .imem_data_i (imem_data_i), + .imem_valid_o (imem_valid_o), + .imem_ack_i (imem_ack_i), + .dmem_addr_o (dmem_addr_o), + .dmem_data_i (dmem_data_i), + .dmem_data_o (dmem_data_o), + .dmem_sel_o (dmem_sel_o), + .dmem_we_o (dmem_we_o), + .dmem_valid_o (dmem_valid_o), + .dmem_ack_i (dmem_ack_i) + ); endmodule \ No newline at end of file diff --git a/rtl/AtomBones_Config.vh b/rtl/AtomBones_Config.vh new file mode 100644 index 00000000..8cea5e90 --- /dev/null +++ b/rtl/AtomBones_Config.vh @@ -0,0 +1,24 @@ +`ifndef __HYDROGENSOC_CONFIG_VH__ +`define __HYDROGENSOC_CONFIG_VH__ + +// Reset address +`define SOC_RESET_ADDRESS 32'h00000000 + +// Atombones doesn't need the following parameters since everything +// other that the core is software simulated + +// SoC Peripherals + +// IRAM +// `define IRAM_ADDR 32'h00000000 // 0 GB boundry +// `define IRAM_SIZE 32'h00008000 // 32 KB + +// // RAM +// `define RAM_ADDR 32'h04000000 // 0.5 GB boundry +// `define RAM_SIZE 32'h00002000 // 8 KB + +// // UART +// `define UART_ADDR 32'h08000000 // 1.0 GB boundry +// `define UART_SIZE 32'h00000008 // 8 bytes + +`endif //__HYDROGENSOC_CONFIG_VH__ \ No newline at end of file diff --git a/rtl/Config.vh b/rtl/Config.vh deleted file mode 100644 index 97967a61..00000000 --- a/rtl/Config.vh +++ /dev/null @@ -1,30 +0,0 @@ -// Config file -`define RESET_PC_ADDRESS 32'h0000000 - -`define __NOP_INSTRUCTION__ 32'h00000013 // NOP = addi x0, x0, 0 - -// IMM_TYPE -`define __I_IMMIDIATE__ 3'd0 -`define __S_IMMIDIATE__ 3'd1 -`define __B_IMMIDIATE__ 3'd2 -`define __U_IMMIDIATE__ 3'd3 -`define __J_IMMIDIATE__ 3'd4 - -// ALU -`define __ALU_ADD__ 3'd0 -`define __ALU_SUB__ 3'd1 -`define __ALU_XOR__ 3'd2 -`define __ALU_OR__ 3'd3 -`define __ALU_AND__ 3'd4 -`define __ALU_SLL__ 3'd5 -`define __ALU_SRL__ 3'd6 -`define __ALU_SRA__ 3'd7 - -// COMPARATOR -`define __CMP_UN__ 3'd0 -`define __CMP_EQ__ 3'd1 -`define __CMP_NQ__ 3'd2 -`define __CMP_LT__ 3'd3 -`define __CMP_GE__ 3'd4 -`define __CMP_LTU__ 3'd5 -`define __CMP_GEU__ 3'd6 diff --git a/rtl/HydrogenSoC.v b/rtl/HydrogenSoC.v index a09e7fa5..0c454731 100644 --- a/rtl/HydrogenSoC.v +++ b/rtl/HydrogenSoC.v @@ -1,7 +1,13 @@ -`default_nettype none +/////////////////////////////////////////////////////////////////// +// File : HydrogenSoC.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : HydrogenSoC is an FPGA ready SoC, it consists of +// a single atom core with memories and communication modules. +/////////////////////////////////////////////////////////////////// `include "Timescale.vh" -`include "Config.vh" +`include "HydrogenSoC_Config.vh" + `include "core/AtomRV_wb.v" `include "uncore/DualPortRAM_wb.v" //`include "uncore/SinglePortROM_wb.v" @@ -10,52 +16,49 @@ `include "uncore/GPIO.v" `ifndef verilator -// Defaults for Xilinx ISE -`define __IMEM_INIT_FILE__ "code.hex" -`define __DMEM_INIT_FILE__ "data.hex" + // Defaults for Xilinx ISE + `define __IMEM_INIT_FILE__ "code.hex" + `define __DMEM_INIT_FILE__ "data.hex" `endif -/** - * === Hydrogen SoC === - * Barebone SoC housing a single atom core, instruction memory, data memory and a uart slave. - */ +`default_nettype none module HydrogenSoC ( - // GLOBAL SIGNALS - input wire clk_i, - input wire rst_i, - - // GPIO - inout wire [31:0] gpio_io, + // GLOBAL SIGNALS + input wire clk_i, + input wire rst_i, + + // GPIO + inout wire [31:0] gpio_io, // UART input wire uart_usb_rx_i, output wire uart_usb_tx_o, - input wire uart_io_rx_i, + input wire uart_io_rx_i, output wire uart_io_tx_o, - - // UART MUX - input wire uart_mux_sel, - - // TEST POINTS - output wire uart_rx_test_point_o, - output wire uart_tx_test_point_o + + // UART MUX + input wire uart_mux_sel, + + // TEST POINTS + output wire uart_rx_test_point_o, + output wire uart_tx_test_point_o ); - //////////////////////////////////////// - // UART MUX - wire uart_rx = uart_mux_sel ? uart_io_rx_i : uart_usb_rx_i; - - wire uart_tx; - assign uart_io_tx_o = uart_mux_sel ? uart_tx : 1'b1; - assign uart_usb_tx_o = uart_mux_sel ? 1'b1 : uart_tx; - - // TEST POINTS - assign uart_rx_test_point_o = uart_rx; - assign uart_tx_test_point_o = uart_tx; - - + //////////////////////////////////////// + // UART MUX + wire uart_rx = uart_mux_sel ? uart_io_rx_i : uart_usb_rx_i; + + wire uart_tx; + assign uart_io_tx_o = uart_mux_sel ? uart_tx : 1'b1; + assign uart_usb_tx_o = uart_mux_sel ? 1'b1 : uart_tx; + + // TEST POINTS + assign uart_rx_test_point_o = uart_rx; + assign uart_tx_test_point_o = uart_tx; + + ////////////////////////////////////////// // SoC Parameters @@ -68,9 +71,8 @@ module HydrogenSoC wire wb_clk_i = clk_i; wire wb_rst_i = rst_i; - /* verilator lint_off UNUSED */ wire [31:0] wb_ibus_adr_o; - /* verilator lint_on UNUSED */ + `UNUSED_VAR(wb_ibus_adr_o) wire [31:0] wb_ibus_dat_i; wire wb_ibus_ack_i; @@ -84,11 +86,8 @@ module HydrogenSoC wire [3:0] wb_dbus_sel_o /* verilator public */; wire wb_dbus_stb_o /* verilator public */; reg wb_dbus_ack_i /* verilator public */; - - /* verilator lint_off UNUSED */ wire wb_dbus_cyc_o /* verilator public */; - /* verilator lint_on UNUSED */ - + ///////////////////////////////////////////////// @@ -205,7 +204,7 @@ module HydrogenSoC reg wb_uart_stb_i; wire wb_uart_ack_o; - simpleuart_wb uart ( + simpleuart_wb uart ( .wb_clk_i (wb_clk_i), .wb_rst_i (wb_rst_i), @@ -220,7 +219,7 @@ module HydrogenSoC .rx_i (uart_rx), .tx_o (uart_tx) - ); + ); //////////////////////////////////////////////////// @@ -285,28 +284,34 @@ module HydrogenSoC */ reg [3:0] selected_device /* verilator public */; always @(*) begin /* COMBINATORIAL */ - // default - //selected_device = Device_None; - + // default + //selected_device = Device_None; + if(wb_dbus_cyc_o) begin - if(wb_dbus_adr_o < 32'h00008000) + /* verilator lint_off UNSIGNED */ + if(wb_dbus_adr_o >= `IRAM_ADDR && wb_dbus_adr_o < `IRAM_ADDR+`IRAM_SIZE) selected_device = Device_IRAM; + /* verilator lint_on UNSIGNED */ - else if(wb_dbus_adr_o >= 32'h04000000 && wb_dbus_adr_o < 32'h04002000) + else if(wb_dbus_adr_o >= `RAM_ADDR && wb_dbus_adr_o < `RAM_ADDR+`RAM_SIZE) selected_device = Device_RAM; - else if (wb_dbus_adr_o == 32'h08000000 || wb_dbus_adr_o == 32'h08000004) + else if (wb_dbus_adr_o >= `UART_ADDR && wb_dbus_adr_o < `UART_ADDR+`UART_SIZE) selected_device = Device_UART; - - else if (wb_dbus_adr_o == 32'h08000100) // byte addresses 8000010 to 0800001f + + else if (wb_dbus_adr_o >= `GPIO0_ADDR && wb_dbus_adr_o < `GPIO0_ADDR+`GPIO0_SIZE) selected_device = Device_GPIO0; - else if (wb_dbus_adr_o == 32'h08000104) // byte addresses 8000010 to 0800001f + + else if (wb_dbus_adr_o >= `GPIO1_ADDR && wb_dbus_adr_o < `GPIO1_ADDR+`GPIO1_SIZE) selected_device = Device_GPIO1; else begin - selected_device = Device_None; - $display("RTL-ERROR: Unknown Device Selected: 0x%x\nHaulting simulation...", wb_dbus_adr_o); - $finish(); + selected_device = Device_None; + + `ifdef verilator + $display("RTL-ERROR: Unknown Device Selected: 0x%x\nHaulting simulation...", wb_dbus_adr_o); + $finish(); + `endif end end else begin @@ -341,13 +346,13 @@ module HydrogenSoC logic. */ always @(*) begin /* COMBINATORIAL */ - // Defaults - wb_ram_stb_i = 1'b0; + // Defaults + wb_ram_stb_i = 1'b0; wb_iram_stb_i = 1'b0; - wb_uart_stb_i = 1'b0; - wb_gpio0_stb_i = 1'b0; - wb_gpio1_stb_i = 1'b0; - + wb_uart_stb_i = 1'b0; + wb_gpio0_stb_i = 1'b0; + wb_gpio1_stb_i = 1'b0; + case(selected_device) Device_RAM: wb_ram_stb_i = wb_dbus_stb_o; Device_IRAM: wb_iram_stb_i = wb_dbus_stb_o; diff --git a/rtl/HydrogenSoC_Config.vh b/rtl/HydrogenSoC_Config.vh new file mode 100644 index 00000000..4c1fd355 --- /dev/null +++ b/rtl/HydrogenSoC_Config.vh @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////// +// File : HydrogeSoC_Config.vh +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : Configuration file for HydrogenSoC. It defines the +// HydrogensoC related parameters using verilog preprocessor macros. +//////////////////////////////////////////////////////////////////// + +`ifndef __HYDROGENSOC_CONFIG_VH__ +`define __HYDROGENSOC_CONFIG_VH__ + +// Reset address +`define SOC_RESET_ADDRESS 32'h00000000 + +// SoC Peripherals + +// IRAM +`define IRAM_ADDR 32'h00000000 // 0 GB boundry +`define IRAM_SIZE 32'h00008000 // 32 KB + +// RAM +`define RAM_ADDR 32'h04000000 // 0.5 GB boundry +`define RAM_SIZE 32'h00002000 // 8 KB + +// UART +`define UART_ADDR 32'h08000000 // 1.0 GB boundry +`define UART_SIZE 32'h00000008 // 8 bytes + +// GPIO 0 +`define GPIO0_ADDR 32'h08000100 +`define GPIO0_SIZE 32'h00000004 // 4 bytes + +// GPIO 1 +`define GPIO1_ADDR 32'h08000104 +`define GPIO1_SIZE 32'h00000004 // 4 bytes + + +`endif // __HYDROGENSOC_CONFIG_VH__ diff --git a/rtl/Timescale.vh b/rtl/Timescale.vh index 0bcfdef3..fc3511b9 100644 --- a/rtl/Timescale.vh +++ b/rtl/Timescale.vh @@ -1 +1,12 @@ -`timescale 1ns/1ps \ No newline at end of file +/////////////////////////////////////////////////////////////////// +// File : Timescale.vh +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : Timescale header file +/////////////////////////////////////////////////////////////////// + +`ifndef __TIMESCALE_VH__ +`define __TIMESCALE_VH__ + +`timescale 1ns/1ps + +`endif // __TIMESCALE_VH__ \ No newline at end of file diff --git a/rtl/core/Alu.v b/rtl/core/Alu.v index 85808d1d..d9b63ce5 100644 --- a/rtl/core/Alu.v +++ b/rtl/core/Alu.v @@ -1,38 +1,94 @@ //////////////////////////////////////////////////////////////////// -// RISC-V Atom -// -// File : Alu.v -// -// Description : Arithmetic and logic unit for Atom core +// File : Alu.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : Arithmetic and logic unit for Atom core, following +// Operations are built into the alu: +// - Addition +// - Subtraction +// - Bitwise XOR +// - Bitwise OR, +// - Bitwise AND, +// - Logical Shift Left (Single Cycle) +// - Logical Shift Right (Single Cycle) +// - Arthmetic Shift Right (Single Cycle) //////////////////////////////////////////////////////////////////// -`default_nettype none `include "../Timescale.vh" +`include "Defs.vh" + +`default_nettype none module Alu ( - input wire [31:0] A, - input wire [31:0] B, - input wire [2:0] Sel, + input wire [31:0] a_i, + input wire [31:0] b_i, + input wire [2:0] sel_i, - output reg [31:0] Out + output reg [31:0] result_o ); -wire signed [31:0] A_s = A; + wire sel_add = (sel_i == `ALU_FUNC_ADD); + wire sel_sub = (sel_i == `ALU_FUNC_SUB); + wire sel_xor = (sel_i == `ALU_FUNC_XOR); + wire sel_or = (sel_i == `ALU_FUNC_OR); + wire sel_and = (sel_i == `ALU_FUNC_AND); + wire sel_sll = (sel_i == `ALU_FUNC_SLL); + wire sel_srl = (sel_i == `ALU_FUNC_SRL); + wire sel_sra = (sel_i == `ALU_FUNC_SRA); + + // Result of arithmetic calculations (ADD/SUB) + wire [31:0] arith_result = a_i + (sel_sub ? ((~b_i)+1) : b_i); + + // Bitreverse + function [31:0] reverse; + input [31:0] ain; + integer i; + begin + for(i=0; i<32; i=i+1) begin + reverse[32-1-i] = ain[i]; + end + end + endfunction + + // Input to the universal shifter + reg signed [32:0] shift_input; + always @(*) begin + if (sel_srl) + shift_input = {1'b0, a_i}; + else if (sel_sra) + shift_input = {a_i[31], a_i}; + else // if (sel_sll) // this case includes "sel_sll" + shift_input = {1'b0, reverse(a_i)}; + end + + /* verilator lint_off UNUSED */ + wire [32:0] shift_output = shift_input >>> b_i[4:0]; // Universal shifter + /* verilator lint_on UNUSED */ -always @(*) begin - case(Sel) - `__ALU_ADD__: Out = A + B; - `__ALU_SUB__: Out = A - B; - `__ALU_XOR__: Out = A ^ B; - `__ALU_OR__ : Out = A | B; - `__ALU_AND__: Out = A & B; - `__ALU_SLL__: Out = A << B[4:0]; - `__ALU_SRL__: Out = A >> B[4:0]; - `__ALU_SRA__: Out = A_s >>> B[4:0]; + // output of universal shifter + reg [31:0] final_shift_output; + always @(*) begin + if (sel_sll) + final_shift_output = reverse(shift_output[31:0]); + else + final_shift_output = shift_output[31:0]; + end + + // Final output mux + always @(*) begin + if (sel_add | sel_sub) + result_o = arith_result; + else if (sel_sll | sel_srl | sel_sra) + result_o = final_shift_output; + else if (sel_xor) + result_o = a_i ^ b_i; + else if (sel_or) + result_o = a_i | b_i; + else if (sel_and) + result_o = a_i & b_i; + else + result_o = arith_result; + end - default: Out = 32'd0; - endcase -end endmodule \ No newline at end of file diff --git a/rtl/core/AtomRV.v b/rtl/core/AtomRV.v index 40ba8b1c..a0db686f 100644 --- a/rtl/core/AtomRV.v +++ b/rtl/core/AtomRV.v @@ -5,24 +5,22 @@ // / _, _// / ___/ / /___ | |/ / / /_/ / /_/ /_/ / / / / / / // /_/ |_/___//____/\____/ |___/ \__,_/\__/\____/_/ /_/ /_/ // -// File : AtomRV.v -// Author : Saurabh Singh (saurabh.s99100@gmail.com) -// Description: Nano-RISCV core is a non pipelined embedded class -// 32 bit RISCV core. It is based on RV32I ISA -// +// File : AtomRV.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : Atom is a 2-stage pipelined embedded class 32-bit +// RISCV core. It is based on RV32I ISA /////////////////////////////////////////////////////////////////// -`default_nettype none - -`define __R0_IS_ZERO__ `include "../Timescale.vh" -`include "../Config.vh" +`include "Defs.vh" `include "Decode.v" `include "RegisterFile.v" `include "Alu.v" `include "CSR_Unit.v" +`default_nettype none + module AtomRV ( // ========== General ========== @@ -50,436 +48,436 @@ module AtomRV output wire dmem_valid_o, // DMEM Valid signal input wire dmem_ack_i // DMEM Ack signal ); -/* - ///////////// Protocol specification ////////////// - CPU has a generic handshaking protocol interface (GHPI). Handshaking is done via means - of two signals 'valid' & 'ack'. Valid signal is set by master whenever a transaction - begins and slave responds by setting the 'ack' signal. When both signals are set, - transaction takes place. GHPI protocol also supports delayed transactions. - - CPU has two GHPI ports namely imem & dmem ports. imem port is used only for reading - the memory while dmem pot is used for both eads and writes. The CPU ca ne configured in - both Harvard and Von-Neumann fashion. In case of Harvard configuration, separate instruction - and data memory ae needed to be connected. In case of Von-Neumann mode, a bus arbiter is - needed to multiplex between both ports. - - Reads: - - Master sets the address, the valid signal and clears the strobe signal. - - Slave responds by providing the data corresponding to that address & setting the ack signal. - - Writes: - - Master sets the address, the data, the valid signal and the strobe signal (depending on - the write width). - - Slave responds by setting the ack signal. -*/ - -wire jump_decision = d_jump_en & comparison_result; // final jump decision signal - -//////////////////////////////////////////////////////////////////// -// PIPELINE CONTROL -/* - Raw handshaking signal: These signals make the handshaking of ibus - Fetch stage relies on the imem handshake signal to increment PC. - - We dont ever need to ignore the dmem handshake because ignoring dmem handshake only happens if - currently executing instruction happens to be a load-store instruction, but since currrent - instruction is a jump, there is no memory request made anyways. -*/ -wire raw_imem_handshake = (imem_valid_o && imem_ack_i); - -wire imem_handshake = raw_imem_handshake && !ignore_imem_handshake; -wire dmem_handshake = (dmem_valid_o && dmem_ack_i); - -/* - Definition of stall: - Stall is a state of a pipeline stage in which the current instuction cannot popogate forward. - - Definition of flush: - Flush is defined as insertion of nop in the pipeline in order to prevent an unwanted instuction - to execute. -*/ - -/* - Stall Stage2 in case it has made a memory request and the result has't arrived yet. -*/ -wire waiting_for_dbus_response = (!dmem_handshake && dmem_valid_o); -wire stall_stage2 = waiting_for_dbus_response; - -/* - Stall Stage1 in case: - - Stage1 is waiting for response of a memory request that is has made. - - Stage2 is stalled, since the instruction in stage1 cant popogate to stage2. Therefore until - the stage2 is stalled, instruction in stage1 is kept held. -*/ -wire waiting_for_ibus_response = (!imem_handshake && imem_valid_o); -wire stall_stage1 = waiting_for_ibus_response || stall_stage2; - -/* - Flush pipeline (insert nop in s2) in case: - - there is a jump - - Stage1 is stalled and stage is not, in this case stage can't recieve an new instruction to - execute therefore a bubble is introduced. - - -*/ -wire flush_pipeline = jump_decision || (stall_stage2 ? 0 : stall_stage1); - - -reg ignore_imem_handshake = 0; -always @(posedge clk_i) begin - if(rst_i) - ignore_imem_handshake <= 0; - else begin - case(ignore_imem_handshake) - 0: if(jump_decision) - ignore_imem_handshake <= 1; - - 1: if(raw_imem_handshake) - ignore_imem_handshake <= 0; - endcase - end -end - -//////////////////////////////////////////////////////////////////// -// STAGE 1 - FETCH -//////////////////////////////////////////////////////////////////// -assign imem_valid_o = !rst_i; // Always valid (Except on Reset condition) -/* - Program Counter -*/ -reg [31:0] ProgramCounter /*verilator public*/; -wire [31:0] pc_plus_four = ProgramCounter + 32'd4; - -always @(posedge clk_i) begin - if(rst_i) - ProgramCounter <= `RESET_PC_ADDRESS; - - else if(jump_decision) - ProgramCounter <= {alu_out[31:1], 1'b0}; // Only jump to 16 bit aligned addresses, also JALR enforces this - - else if (!stall_stage1) begin - ProgramCounter <= pc_plus_four; - end -end - -// Connect pc to imem address input -assign imem_addr_o = ProgramCounter; - - -//---------------------------------------------------------- -// PIPELINE REGISTERS -//---------------------------------------------------------- -/* - This register is used to store old value of program counter -*/ -reg [31:0] ProgramCounter_Old /* verilator public */; -always @(posedge clk_i) begin - if(rst_i) - ProgramCounter_Old <= 32'd0; - else if(!stall_stage1) - ProgramCounter_Old <= ProgramCounter; -end - -/* - This register is used to store old value of program counter + 4 -*/ -reg [31:0] link_address; -always @(posedge clk_i) begin - if(rst_i) - link_address <= 32'd0; - else if(!stall_stage1) - link_address <= pc_plus_four; -end - -/* - This register is used to store current instruction that is being - executed -*/ -reg [31:0] InstructionRegister /*verilator public*/; -always @(posedge clk_i) begin - if(rst_i) - InstructionRegister <= `__NOP_INSTRUCTION__; - else begin - if(flush_pipeline) - InstructionRegister <= `__NOP_INSTRUCTION__; - - else if(!stall_stage1) - InstructionRegister <= imem_data_i; + /* + ///////////// Protocol specification ////////////// + CPU has a generic handshaking protocol interface (GHPI). Handshaking is done via means + of two signals 'valid' & 'ack'. Valid signal is set by master whenever a transaction + begins and slave responds by setting the 'ack' signal. When both signals are set, + transaction takes place. GHPI protocol also supports delayed transactions. + + CPU has two GHPI ports namely imem & dmem ports. imem port is used only for reading + the memory while dmem pot is used for both eads and writes. The CPU ca ne configured in + both Harvard and Von-Neumann fashion. In case of Harvard configuration, separate instruction + and data memory ae needed to be connected. In case of Von-Neumann mode, a bus arbiter is + needed to multiplex between both ports. + + Reads: + - Master sets the address, the valid signal and clears the strobe signal. + - Slave responds by providing the data corresponding to that address & setting the ack signal. + + Writes: + - Master sets the address, the data, the valid signal and the strobe signal (depending on + the write width). + - Slave responds by setting the ack signal. + */ + + wire jump_decision = d_jump_en & comparison_result; // final jump decision signal + + //////////////////////////////////////////////////////////////////// + // PIPELINE CONTROL + /* + Raw handshaking signal: These signals make the handshaking of ibus + Fetch stage relies on the imem handshake signal to increment PC. + + We dont ever need to ignore the dmem handshake because ignoring dmem handshake only happens if + currently executing instruction happens to be a load-store instruction, but since currrent + instruction is a jump, there is no memory request made anyways. + */ + wire raw_imem_handshake = (imem_valid_o && imem_ack_i); + + wire imem_handshake = raw_imem_handshake && !ignore_imem_handshake; + wire dmem_handshake = (dmem_valid_o && dmem_ack_i); + + /* + Definition of stall: + Stall is a state of a pipeline stage in which the current instuction cannot popogate forward. + + Definition of flush: + Flush is defined as insertion of nop in the pipeline in order to prevent an unwanted instuction + to execute. + */ + + /* + Stall Stage2 in case it has made a memory request and the result has't arrived yet. + */ + wire waiting_for_dbus_response = (!dmem_handshake && dmem_valid_o); + wire stall_stage2 = waiting_for_dbus_response; + + /* + Stall Stage1 in case: + - Stage1 is waiting for response of a memory request that is has made. + - Stage2 is stalled, since the instruction in stage1 cant popogate to stage2. Therefore until + the stage2 is stalled, instruction in stage1 is kept held. + */ + wire waiting_for_ibus_response = (!imem_handshake && imem_valid_o); + wire stall_stage1 = waiting_for_ibus_response || stall_stage2; + + /* + Flush pipeline (insert nop in s2) in case: + - there is a jump + - Stage1 is stalled and stage is not, in this case stage can't recieve an new instruction to + execute therefore a bubble is introduced. + - + */ + wire flush_pipeline = jump_decision || (stall_stage2 ? 0 : stall_stage1); + + + reg ignore_imem_handshake = 0; + always @(posedge clk_i) begin + if(rst_i) + ignore_imem_handshake <= 0; + else begin + case(ignore_imem_handshake) + 0: if(jump_decision) + ignore_imem_handshake <= 1; + + 1: if(raw_imem_handshake) + ignore_imem_handshake <= 0; + endcase + end end -end - - - -//////////////////////////////////////////////////////////////////// -// STAGE 2 - DECODE & EXECUTE -//////////////////////////////////////////////////////////////////// -/* - ////// Instruction Decode ////// - Instruction decode unit decodes instruction and sets various control - signals throughout the pipeline. Is also extracts immediate values - from instructions and sign extends them properly. -*/ -wire [4:0] d_rd_sel; -wire [4:0] d_rs1_sel; -wire [4:0] d_rs2_sel; -wire [31:0] d_imm; - -wire d_jump_en; -wire [2:0] d_comparison_type; -wire d_rf_we; -wire [2:0] d_rf_din_sel; -wire d_a_op_sel; -wire d_b_op_sel; -wire d_cmp_b_op_sel; -wire [2:0] d_alu_op_sel; -wire [2:0] d_mem_access_width; -wire d_mem_load_store; -wire d_mem_we; -wire [2:0] d_csru_op_sel; -wire d_csru_we; - - -Decode decode -( - .instr_i (InstructionRegister), - - .rd_sel_o (d_rd_sel), - .rs1_sel_o (d_rs1_sel), - .rs2_sel_o (d_rs2_sel), - - .imm_o (d_imm), - - .jump_en_o (d_jump_en), - .comparison_type_o (d_comparison_type), - .rf_we_o (d_rf_we), - .rf_din_sel_o (d_rf_din_sel), - .a_op_sel_o (d_a_op_sel), - .b_op_sel_o (d_b_op_sel), - .cmp_b_op_sel_o (d_cmp_b_op_sel), - .alu_op_sel_o (d_alu_op_sel), - .mem_access_width_o (d_mem_access_width), - .d_mem_load_store (d_mem_load_store), - .mem_we_o (d_mem_we), - .csru_op_sel_o (d_csru_op_sel), - .csru_we_o (d_csru_we) -); - - - -/* - ////// Register File ////// - Contains cpu registers (r0-31) -*/ -// RF_Din Multiplexer -reg [31:0] rf_rd_data; -always @(*) begin - case(d_rf_din_sel) - 3'd0: rf_rd_data = d_imm; - 3'd1: rf_rd_data = link_address; - 3'd2: rf_rd_data = alu_out; - 3'd3: rf_rd_data = {31'd0, comparison_result}; - 3'd4: rf_rd_data = memload; - 3'd5: rf_rd_data = csru_data_o; - - default: rf_rd_data = 32'd0; - endcase -end - -wire [31:0] rf_rs1; -wire [31:0] rf_rs2; - -RegisterFile #(.REG_WIDTH(32), .REG_ADDR_WIDTH(5)) rf -( - .Ra_Sel_i (d_rs1_sel), - .Ra_o (rf_rs1), - - .Rb_Sel_i (d_rs2_sel), - .Rb_o (rf_rs2), + //////////////////////////////////////////////////////////////////// + // STAGE 1 - FETCH + //////////////////////////////////////////////////////////////////// + assign imem_valid_o = !rst_i; // Always valid (Except on Reset condition) + /* + Program Counter + */ + reg [31:0] ProgramCounter /*verilator public*/; + wire [31:0] pc_plus_four = ProgramCounter + 32'd4; + + always @(posedge clk_i) begin + if(rst_i) + ProgramCounter <= `RESET_PC_ADDRESS; + + else if(jump_decision) + ProgramCounter <= {alu_out[31:1], 1'b0}; // Only jump to 16 bit aligned addresses, also JALR enforces this + + else if (!stall_stage1) begin + ProgramCounter <= pc_plus_four; + end + end - .Data_We_i (d_rf_we & !stall_stage2), - .Rd_Sel_i (d_rd_sel), - .Data_i (rf_rd_data), + // Connect pc to imem address input + assign imem_addr_o = ProgramCounter; - .Clk_i (clk_i), - .Rst_i (rst_i) -); + //---------------------------------------------------------- + // PIPELINE REGISTERS + //---------------------------------------------------------- + /* + This register is used to store old value of program counter + */ + reg [31:0] ProgramCounter_Old /* verilator public */; + always @(posedge clk_i) begin + if(rst_i) + ProgramCounter_Old <= 32'd0; + else if(!stall_stage1) + ProgramCounter_Old <= ProgramCounter; + end -/* - ////// ALU ////// - Used for arithmetic and logical computations including shifts. -*/ -wire [31:0] alu_a_in = (d_a_op_sel) ? ProgramCounter_Old : rf_rs1; -wire [31:0] alu_b_in = (d_b_op_sel) ? d_imm : rf_rs2; -wire [31:0] alu_out; + /* + This register is used to store old value of program counter + 4 + */ + reg [31:0] link_address; + always @(posedge clk_i) begin + if(rst_i) + link_address <= 32'd0; + else if(!stall_stage1) + link_address <= pc_plus_four; + end -Alu alu -( - .A (alu_a_in), - .B (alu_b_in), - .Sel (d_alu_op_sel), - .Out (alu_out) -); + /* + This register is used to store current instruction that is being + executed + */ + reg [31:0] InstructionRegister /*verilator public*/ = `RV_INSTR_NOP; + always @(posedge clk_i) begin + if(rst_i) + InstructionRegister <= `RV_INSTR_NOP; + else begin + if(flush_pipeline) + InstructionRegister <= `RV_INSTR_NOP; + + else if(!stall_stage1) + InstructionRegister <= imem_data_i; + end + end -/* - ////// Comparator ////// - Used for all comparative operations -*/ -reg comparison_result; + //////////////////////////////////////////////////////////////////// + // STAGE 2 - DECODE & EXECUTE + //////////////////////////////////////////////////////////////////// + /* + ////// Instruction Decode ////// + Instruction decode unit decodes instruction and sets various control + signals throughout the pipeline. Is also extracts immediate values + from instructions and sign extends them properly. + */ + wire [4:0] d_rd_sel; + wire [4:0] d_rs1_sel; + wire [4:0] d_rs2_sel; + wire [31:0] d_imm; + + wire d_jump_en; + wire [2:0] d_comparison_type; + wire d_rf_we; + wire [2:0] d_rf_din_sel; + wire d_a_op_sel; + wire d_b_op_sel; + wire d_cmp_b_op_sel; + wire [2:0] d_alu_op_sel; + wire [2:0] d_mem_access_width; + wire d_mem_load_store; + wire d_mem_we; + wire [2:0] d_csru_op_sel; + wire d_csru_we; + + + Decode decode + ( + .instr_i (InstructionRegister), + + .rd_sel_o (d_rd_sel), + .rs1_sel_o (d_rs1_sel), + .rs2_sel_o (d_rs2_sel), + + .imm_o (d_imm), + + .jump_en_o (d_jump_en), + .comparison_type_o (d_comparison_type), + .rf_we_o (d_rf_we), + .rf_din_sel_o (d_rf_din_sel), + .a_op_sel_o (d_a_op_sel), + .b_op_sel_o (d_b_op_sel), + .cmp_b_op_sel_o (d_cmp_b_op_sel), + .alu_op_sel_o (d_alu_op_sel), + .mem_access_width_o (d_mem_access_width), + .d_mem_load_store (d_mem_load_store), + .mem_we_o (d_mem_we), + .csru_op_sel_o (d_csru_op_sel), + .csru_we_o (d_csru_we) + ); + + + + /* + ////// Register File ////// + Contains cpu registers (r0-31) + */ + + // RF_Din Multiplexer + reg [31:0] rf_rd_data; + always @(*) begin + case(d_rf_din_sel) + 3'd0: rf_rd_data = d_imm; + 3'd1: rf_rd_data = link_address; + 3'd2: rf_rd_data = alu_out; + 3'd3: rf_rd_data = {31'd0, comparison_result}; + 3'd4: rf_rd_data = memload; + 3'd5: rf_rd_data = csru_data_o; + + default: rf_rd_data = 32'd0; + endcase + end -wire [31:0] cmp_A = rf_rs1; -wire [31:0] cmp_B = (d_cmp_b_op_sel) ? d_imm : rf_rs2; -wire signed [31:0] cmp_A_signed = cmp_A; -wire signed [31:0] cmp_B_signed = cmp_B; + wire [31:0] rf_rs1; + wire [31:0] rf_rs2; + + RegisterFile #(.REG_WIDTH(32), .REG_ADDR_WIDTH(5)) rf + ( + .Ra_Sel_i (d_rs1_sel), + .Ra_o (rf_rs1), + + .Rb_Sel_i (d_rs2_sel), + .Rb_o (rf_rs2), + + .Data_We_i (d_rf_we & !stall_stage2), + .Rd_Sel_i (d_rd_sel), + .Data_i (rf_rd_data), + + .Clk_i (clk_i), + .Rst_i (rst_i) + ); + + + /* + ////// ALU ////// + Used for arithmetic and logical computations including shifts. + */ + wire [31:0] alu_a_in = (d_a_op_sel) ? ProgramCounter_Old : rf_rs1; + wire [31:0] alu_b_in = (d_b_op_sel) ? d_imm : rf_rs2; + wire [31:0] alu_out; + + Alu alu + ( + .a_i (alu_a_in), + .b_i (alu_b_in), + .sel_i (d_alu_op_sel), + .result_o (alu_out) + ); + + + + /* + ////// Comparator ////// + Used for all comparative operations + */ + reg comparison_result; + + wire [31:0] cmp_A = rf_rs1; + wire [31:0] cmp_B = (d_cmp_b_op_sel) ? d_imm : rf_rs2; + wire signed [31:0] cmp_A_signed = cmp_A; + wire signed [31:0] cmp_B_signed = cmp_B; + + always @(*) /* COMBINATORIAL*/ + begin + case(d_comparison_type) + `CMP_FUNC_UN: comparison_result = 1'b1; + `CMP_FUNC_EQ: comparison_result = (cmp_A == cmp_B); + `CMP_FUNC_NQ: comparison_result = (cmp_A != cmp_B); + `CMP_FUNC_LT: comparison_result = (cmp_A_signed < cmp_B_signed); + `CMP_FUNC_GE: comparison_result = (cmp_A_signed >= cmp_B_signed); + `CMP_FUNC_LTU: comparison_result = (cmp_A < cmp_B); + `CMP_FUNC_GEU: comparison_result = (cmp_A >= cmp_B); + + default: comparison_result = 1'b0; + endcase + end -always @(*) /* COMBINATORIAL*/ -begin - case(d_comparison_type) - `__CMP_UN__ : comparison_result = 1'b1; - `__CMP_EQ__ : comparison_result = (cmp_A == cmp_B); - `__CMP_NQ__ : comparison_result = (cmp_A != cmp_B); - `__CMP_LT__ : comparison_result = (cmp_A_signed < cmp_B_signed); - `__CMP_GE__ : comparison_result = (cmp_A_signed >= cmp_B_signed); - `__CMP_LTU__ : comparison_result = (cmp_A < cmp_B); - `__CMP_GEU__ : comparison_result = (cmp_A >= cmp_B); - default: comparison_result = 1'b0; - endcase -end + /* + ////// CSR Unit ////// + Contains all the Control and status registers + */ + wire [11:0] csru_addr_i = d_imm[11:0]; + wire [31:0] csru_data_o; + // check if it is imm type CSR instruction and send data_i accordingly + wire [31:0] csru_data_i = d_csru_op_sel[2] ? {{27{1'b0}}, d_rs1_sel} : rf_rs1; -/* - ////// CSR Unit ////// - Contains all the Control and status registers -*/ -wire [11:0] csru_addr_i = d_imm[11:0]; -wire [31:0] csru_data_o; + CSR_Unit csr_unit + ( + // Global signals + .clk_i (clk_i), + .rst_i (rst_i), -// check if it is imm type CSR instruction and send data_i accordingly -wire [31:0] csru_data_i = d_csru_op_sel[2] ? {{27{1'b0}}, d_rs1_sel} : rf_rs1; + // Signals for Reading from / Writing to CSRs + .addr_i (csru_addr_i), + .data_i (csru_data_i), + .op_i (d_csru_op_sel[1:0]), + .we_i (d_csru_we), + .data_o (csru_data_o) + ); -CSR_Unit csr_unit -( - // Global signals - .clk_i (clk_i), - .rst_i (rst_i), - - // Signals for Reading from / Writing to CSRs - .addr_i (csru_addr_i), - .data_i (csru_data_i), - .op_i (d_csru_op_sel[1:0]), - .we_i (d_csru_we), - .data_o (csru_data_o) -); + /* + DATA MEMORY ACCESS + */ + wire [31:0] dmem_address = alu_out; + wire [31:0] dmem_data_out = rf_rs2; -/* - DATA MEMORY ACCESS -*/ -wire [31:0] dmem_address = alu_out; -wire [31:0] dmem_data_out = rf_rs2; - -assign dmem_addr_o = {dmem_address[31:2], {2{1'b0}}}; // word aligned accesses -assign dmem_valid_o = d_mem_load_store; -assign dmem_we_o = d_mem_we;// & !stall_stage2; IMPORTANT - -///////////////////////////////// -// READ - -/* - ////// MEM_LOAD ////// -*/ -reg [31:0] memload; - -always @(*) /* COMBINATORIAL */ -begin - case(d_mem_access_width[1:0]) - 2'b00: begin // Load Byte - case(dmem_address[1:0]) - 2'b00: memload = {{24{d_mem_access_width[2] ? 1'b0 : dmem_data_i[7]}}, dmem_data_i[7:0]}; - 2'b01: memload = {{24{d_mem_access_width[2] ? 1'b0 : dmem_data_i[15]}}, dmem_data_i[15:8]}; - 2'b10: memload = {{24{d_mem_access_width[2] ? 1'b0 : dmem_data_i[23]}}, dmem_data_i[23:16]}; - 2'b11: memload = {{24{d_mem_access_width[2] ? 1'b0 : dmem_data_i[31]}}, dmem_data_i[31:24]}; - endcase - end - - 2'b01: begin // Load Half Word - case(dmem_address[1]) - 1'b0: memload = {{16{d_mem_access_width[2] ? 1'b0 : dmem_data_i[15]}}, dmem_data_i[15:0]}; - 1'b1: memload = {{16{d_mem_access_width[2] ? 1'b0 : dmem_data_i[31]}}, dmem_data_i[31:16]}; - endcase - end - - 2'b10: begin // Load Word - memload = dmem_data_i; - end + assign dmem_addr_o = {dmem_address[31:2], {2{1'b0}}}; // word aligned accesses + assign dmem_valid_o = d_mem_load_store; + assign dmem_we_o = d_mem_we;// & !stall_stage2; IMPORTANT - default: memload = 32'h00000000; - endcase -end + ///////////////////////////////// + // READ -//////////////////////////////// -// WRITE + /* + ////// MEM_LOAD ////// + */ + reg [31:0] memload; -// Setting the sel_o signal -always @(*) begin /* COMBINATORIAL */ - if (d_mem_we) begin + always @(*) /* COMBINATORIAL */ + begin case(d_mem_access_width[1:0]) - 2'b00: begin // Store byte + 2'b00: begin // Load Byte case(dmem_address[1:0]) - 2'b00: dmem_sel_o = 4'b0001; - 2'b01: dmem_sel_o = 4'b0010; - 2'b10: dmem_sel_o = 4'b0100; - 2'b11: dmem_sel_o = 4'b1000; + 2'b00: memload = {{24{d_mem_access_width[2] ? 1'b0 : dmem_data_i[7]}}, dmem_data_i[7:0]}; + 2'b01: memload = {{24{d_mem_access_width[2] ? 1'b0 : dmem_data_i[15]}}, dmem_data_i[15:8]}; + 2'b10: memload = {{24{d_mem_access_width[2] ? 1'b0 : dmem_data_i[23]}}, dmem_data_i[23:16]}; + 2'b11: memload = {{24{d_mem_access_width[2] ? 1'b0 : dmem_data_i[31]}}, dmem_data_i[31:24]}; endcase end - - 2'b01: begin // Store Half Word + + 2'b01: begin // Load Half Word case(dmem_address[1]) - 1'b0: dmem_sel_o = 4'b0011; - 1'b1: dmem_sel_o = 4'b1100; + 1'b0: memload = {{16{d_mem_access_width[2] ? 1'b0 : dmem_data_i[15]}}, dmem_data_i[15:0]}; + 1'b1: memload = {{16{d_mem_access_width[2] ? 1'b0 : dmem_data_i[31]}}, dmem_data_i[31:16]}; endcase end + + 2'b10: begin // Load Word + memload = dmem_data_i; + end - 2'b10: dmem_sel_o = 4'b1111; // Store Word - - default: dmem_sel_o = 4'b1111; - endcase + default: memload = 32'h00000000; + endcase end - else - dmem_sel_o = 4'b1111; // Load (Byte/HWord/Word) -end + //////////////////////////////// + // WRITE + + // Setting the sel_o signal + always @(*) begin /* COMBINATORIAL */ + if (d_mem_we) begin + case(d_mem_access_width[1:0]) + 2'b00: begin // Store byte + case(dmem_address[1:0]) + 2'b00: dmem_sel_o = 4'b0001; + 2'b01: dmem_sel_o = 4'b0010; + 2'b10: dmem_sel_o = 4'b0100; + 2'b11: dmem_sel_o = 4'b1000; + endcase + end + + 2'b01: begin // Store Half Word + case(dmem_address[1]) + 1'b0: dmem_sel_o = 4'b0011; + 1'b1: dmem_sel_o = 4'b1100; + endcase + end + + 2'b10: dmem_sel_o = 4'b1111; // Store Word + + default: dmem_sel_o = 4'b1111; + endcase + end + else + dmem_sel_o = 4'b1111; // Load (Byte/HWord/Word) + end -// Setting the data_o signal -always @(*) begin /* COMBINATORIAL */ - if (d_mem_we) begin - case(d_mem_access_width[1:0]) - 2'b00: begin // Store byte - case(dmem_address[1:0]) - 2'b00: dmem_data_o = { {24{1'b0}}, dmem_data_out[7:0] }; - 2'b01: dmem_data_o = { {16{1'b0}}, dmem_data_out[7:0], {8{1'b0}} }; - 2'b10: dmem_data_o = { {8{1'b0}} , dmem_data_out[7:0], {16{1'b0}} }; - 2'b11: dmem_data_o = { dmem_data_out[7:0], {24{1'b0}} }; - endcase - end - - 2'b01: begin // Store Half Word - case(dmem_address[1]) - 1'b0: dmem_data_o = { {16{1'b0}}, dmem_data_out[15:0] }; - 1'b1: dmem_data_o = { dmem_data_out[15:0], {16{1'b0}} }; - endcase - end - - 2'b10: dmem_data_o = dmem_data_out; // Store Word - default: dmem_data_o = dmem_data_out; - endcase + // Setting the data_o signal + always @(*) begin /* COMBINATORIAL */ + if (d_mem_we) begin + case(d_mem_access_width[1:0]) + 2'b00: begin // Store byte + case(dmem_address[1:0]) + 2'b00: dmem_data_o = { {24{1'b0}}, dmem_data_out[7:0] }; + 2'b01: dmem_data_o = { {16{1'b0}}, dmem_data_out[7:0], {8{1'b0}} }; + 2'b10: dmem_data_o = { {8{1'b0}} , dmem_data_out[7:0], {16{1'b0}} }; + 2'b11: dmem_data_o = { dmem_data_out[7:0], {24{1'b0}} }; + endcase + end + + 2'b01: begin // Store Half Word + case(dmem_address[1]) + 1'b0: dmem_data_o = { {16{1'b0}}, dmem_data_out[15:0] }; + 1'b1: dmem_data_o = { dmem_data_out[15:0], {16{1'b0}} }; + endcase + end + + 2'b10: dmem_data_o = dmem_data_out; // Store Word + + default: dmem_data_o = dmem_data_out; + endcase + end + else + dmem_data_o = 32'h00000000; // Load (Byte/HWord/Word) end - else - dmem_data_o = 32'h00000000; // Load (Byte/HWord/Word) -end endmodule \ No newline at end of file diff --git a/rtl/core/AtomRV_wb.v b/rtl/core/AtomRV_wb.v index 3dd50829..6ee7993c 100644 --- a/rtl/core/AtomRV_wb.v +++ b/rtl/core/AtomRV_wb.v @@ -1,20 +1,27 @@ -`default_nettype none +//////////////////////////////////////////////////////////////////// +// File : AtomRV_wb.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : Wishbone wrapper for Atom core +//////////////////////////////////////////////////////////////////// + `include "AtomRV.v" +`default_nettype none + /* Wishbone wrapper for the atom cpu. */ module AtomRV_wb ( - input wire wb_clk_i, + input wire wb_clk_i, input wire wb_rst_i, - // === IBUS Wishbone Master Interface === - output wire [31:0] wb_ibus_adr_o, + // === IBUS Wishbone Master Interface === + output wire [31:0] wb_ibus_adr_o, input wire [31:0] wb_ibus_dat_i, - output wire wb_ibus_stb_o, - input wire wb_ibus_ack_i, + output wire wb_ibus_stb_o, + input wire wb_ibus_ack_i, // === DBUS Wishbone Master Interface === output wire [31:0] wb_dbus_adr_o, @@ -33,84 +40,68 @@ module AtomRV_wb //output reg [31:0] eoi ); ///////////////////////////////////////////////////////////////// - wire [31:0] imem_addr_o; // IMEM Address - wire [31:0] imem_data_i; // IMEM data + wire [31:0] imem_addr_o; // IMEM Address + wire [31:0] imem_data_i; // IMEM data - wire imem_valid_o; // DMEM Access width - wire imem_ack_i; // DMEM WriteEnable + wire imem_valid_o; // IMEM valid + wire imem_ack_i; // IMEM Acknowledge - wire [31:0] dmem_addr_o; // DMEM address - wire [31:0] dmem_data_i; // DMEM data in - wire [31:0] dmem_data_o; // DMEM data out - - wire [3:0] dmem_sel_o; // DMEM Access width - wire dmem_we_o; // DMEM Access width - wire dmem_valid_o; // DMEM Access width - wire dmem_ack_i; // DMEM WriteEnable + wire [31:0] dmem_addr_o; // DMEM address + wire [31:0] dmem_data_i; // DMEM data in + wire [31:0] dmem_data_o; // DMEM data out - // Core - AtomRV atom_core - ( - .clk_i (wb_clk_i), - .rst_i (wb_rst_i), - - .imem_addr_o (imem_addr_o), - .imem_data_i (imem_data_i), - - .imem_valid_o (imem_valid_o), - .imem_ack_i (imem_ack_i), + wire [3:0] dmem_sel_o; // DMEM Access width + wire dmem_we_o; // DMEM Access width + wire dmem_valid_o; // DMEM Access width + wire dmem_ack_i; // DMEM WriteEnable + + // Atom Core + AtomRV atom_core + ( + .clk_i (wb_clk_i), + .rst_i (wb_rst_i), - .dmem_addr_o (dmem_addr_o), - .dmem_data_i (dmem_data_i), - .dmem_data_o (dmem_data_o), + .imem_addr_o (imem_addr_o), + .imem_data_i (imem_data_i), - .dmem_sel_o (dmem_sel_o), - .dmem_we_o (dmem_we_o), + .imem_valid_o (imem_valid_o), + .imem_ack_i (imem_ack_i), - .dmem_valid_o (dmem_valid_o), - .dmem_ack_i (dmem_ack_i) - ); - - //////////////////////////////////////////////////////////// - /// IBUS Wishbone Logic - // parameter IDLE = 0; - // parameter WAIT = 1; - // reg state = IDLE; + .dmem_addr_o (dmem_addr_o), + .dmem_data_i (dmem_data_i), + .dmem_data_o (dmem_data_o), - // always @(posedge wb_clk_i) begin - // wb_ibus_stb_o <= 0; - // case(state) - // IDLE: if(imem_valid_o) begin - // wb_ibus_stb_o <= 1; - // state <= WAIT; - // end + .dmem_sel_o (dmem_sel_o), + .dmem_we_o (dmem_we_o), - // WAIT: if(imem_ack_i) - // state <= IDLE; + .dmem_valid_o (dmem_valid_o), + .dmem_ack_i (dmem_ack_i) + ); + + //////////////////////////////////////////////////////////// + /// IBUS Wishbone Logic - // endcase - // end + assign wb_ibus_adr_o = imem_addr_o; + assign imem_data_i = wb_ibus_dat_i; + assign wb_ibus_stb_o = imem_valid_o; + assign imem_ack_i = wb_ibus_ack_i; - assign wb_ibus_adr_o = imem_addr_o; - assign imem_data_i = wb_ibus_dat_i; - assign wb_ibus_stb_o = imem_valid_o; - assign imem_ack_i = wb_ibus_ack_i; - //////////////////////////////////////////////////////////// - /// DBUS Wishbone Logic - assign wb_dbus_adr_o = dmem_addr_o; - assign dmem_data_i = wb_dbus_dat_i; - assign wb_dbus_dat_o = dmem_data_o; + //////////////////////////////////////////////////////////// + /// DBUS Wishbone Logic + assign wb_dbus_adr_o = dmem_addr_o; + assign dmem_data_i = wb_dbus_dat_i; + assign wb_dbus_dat_o = dmem_data_o; - assign wb_dbus_sel_o = dmem_sel_o; - assign wb_dbus_we_o = dmem_we_o; + assign wb_dbus_sel_o = dmem_sel_o; + assign wb_dbus_we_o = dmem_we_o; - assign wb_dbus_stb_o = dmem_valid_o; - assign dmem_ack_i = wb_dbus_ack_i; + assign wb_dbus_stb_o = dmem_valid_o; + assign dmem_ack_i = wb_dbus_ack_i; - assign wb_dbus_cyc_o = wb_dbus_stb_o; + assign wb_dbus_cyc_o = wb_dbus_stb_o; endmodule \ No newline at end of file diff --git a/rtl/core/CSR_Unit.v b/rtl/core/CSR_Unit.v index 03e61d49..fdb3888f 100644 --- a/rtl/core/CSR_Unit.v +++ b/rtl/core/CSR_Unit.v @@ -1,3 +1,13 @@ +//////////////////////////////////////////////////////////////////// +// File : CSR_Unit.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : Control & Status Register (CSR) unit contains logic +// to read and write to the CSR registers +//////////////////////////////////////////////////////////////////// + +`include "Utils.vh" +`include "Defs.vh" + `default_nettype none module CSR_Unit @@ -10,9 +20,7 @@ module CSR_Unit input wire [11:0] addr_i, input wire [31:0] data_i, input wire [1:0] op_i, - /* verilator lint_off UNUSED */ input wire we_i, - /* verilator lint_on UNUSED */ output wire [31:0] data_o @@ -20,65 +28,65 @@ module CSR_Unit // ouput signals to pipeline ); - - -/* Generate Data to be written */ -/* verilator lint_off UNUSED */ -reg [31:0] write_value; // Value to be written onto a CSR register -/* verilator lint_on UNUSED */ -reg [31:0] read_value; // Value of selected CSR register - -always @(*) /* COMBINATIONAL */ begin - case(op_i[1:0]) - 2'b00: write_value = data_i; // CSRRW - 2'b01: write_value = data_i & read_value; // CSRRS - 2'b10: write_value = ~(data_i & read_value); // CSRRC - - default: - write_value = read_value; - endcase -end - -//////////////////////////////////////////////////////////// -// CSR Registers - -// CYCLE (Read-Only) -reg [63:0] csr_cycle = 64'd0; - -always @(posedge clk_i) begin - if(rst_i) - csr_cycle <= 64'd0; - else - csr_cycle <= csr_cycle + 1'b1; -end - - -//////////////////////////////////////////////////////////// -// CSR Selection - -// assigns the read value function to various CSRs and sets we -// pins of CSRs (if not Readonly) - -always @(*) /* COMBINATIONAL */ begin - // Defaults - read_value = 0; - - case(addr_i) - 12'hc00: begin - read_value = csr_cycle[31:0]; - end - - 12'hc80: begin - read_value = csr_cycle[63:32]; - end - - default: begin - read_value = 0; - end - - endcase -end - -assign data_o = read_value; + `UNUSED_VAR(we_i) + + // Generate Data to be written + reg [31:0] write_value; // Value to be written onto a CSR register + `UNUSED_VAR(write_value) + + reg [31:0] read_value; // Value of selected CSR register + + always @(*) /* COMBINATIONAL */ begin + case(op_i[1:0]) + 2'b00: write_value = data_i; // CSRRW + 2'b01: write_value = data_i & read_value; // CSRRS + 2'b10: write_value = ~(data_i & read_value); // CSRRC + + default: + write_value = read_value; + endcase + end + + //////////////////////////////////////////////////////////// + // CSR Registers + + // CYCLE (Read-Only) + reg [63:0] csr_cycle = 64'd0; + + always @(posedge clk_i) begin + if(rst_i) + csr_cycle <= 64'd0; + else + csr_cycle <= csr_cycle + 1'b1; + end + + + //////////////////////////////////////////////////////////// + // CSR Selection + + // assigns the read value function to various CSRs and sets we + // pins of CSRs (if not Readonly) + + always @(*) /* COMBINATIONAL */ begin + // Defaults + read_value = 0; + + case(addr_i) + 12'hc00: begin + read_value = csr_cycle[31:0]; + end + + 12'hc80: begin + read_value = csr_cycle[63:32]; + end + + default: begin + read_value = 0; + end + + endcase + end + + assign data_o = read_value; endmodule diff --git a/rtl/core/Decode.v b/rtl/core/Decode.v index b8ca2447..beb799f0 100644 --- a/rtl/core/Decode.v +++ b/rtl/core/Decode.v @@ -1,9 +1,7 @@ //////////////////////////////////////////////////////////////////// -// RISC-V Atom -// // File : Decode.v // Author : Saurabh Singh (saurabh.s99100@gmail.com) -// Description : Instruction Decoder for RISCV atom core +// Description : Instruction Decoder for RISCV atom core //////////////////////////////////////////////////////////////////// `default_nettype none @@ -34,425 +32,425 @@ module Decode output reg csru_we_o ); -// Decode fields -wire [6:0] opcode = instr_i[6:0]; -wire [2:0] func3 = instr_i[14:12]; -wire [6:0] func7 = instr_i[31:25]; - -assign mem_access_width_o = func3; -assign csru_op_sel_o = func3; - -assign rd_sel_o = instr_i[11:7]; -assign rs1_sel_o = instr_i[19:15]; -assign rs2_sel_o = instr_i[24:20]; - -reg [2:0] imm_format; - -/* - Decode Immediate -*/ -reg [31:0] getExtImm; - -always @(*) /*COMBINATORIAL*/ -begin - case(imm_format) - `__I_IMMIDIATE__ : getExtImm = {{21{instr_i[31]}}, instr_i[30:25], instr_i[24:21], instr_i[20]}; - `__S_IMMIDIATE__ : getExtImm = {{21{instr_i[31]}}, instr_i[30:25], instr_i[11:8], instr_i[7]}; - `__B_IMMIDIATE__ : getExtImm = {{20{instr_i[31]}}, instr_i[7], instr_i[30:25], instr_i[11:8], 1'b0}; - `__U_IMMIDIATE__ : getExtImm = {instr_i[31], instr_i[30:20], instr_i[19:12], {12{1'b0}}}; - `__J_IMMIDIATE__ : getExtImm = {{12{instr_i[31]}}, instr_i[19:12], instr_i[20], instr_i[30:25], instr_i[24:21], 1'b0}; - - default: - getExtImm = 32'd0; - endcase -end - -assign imm_o = getExtImm; - - -always @(*) begin - // DEFAULT VALUES - jump_en_o = 1'b0; - comparison_type_o = `__CMP_UN__; - rf_we_o = 1'b0; - rf_din_sel_o = 3'd0; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - cmp_b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_ADD__; - mem_we_o = 1'b0; - d_mem_load_store = 1'b0; - imm_format = `__U_IMMIDIATE__; - csru_we_o = 0; - - - casez({func7, func3, opcode}) - - /* LUI */ - 17'b???????_???_0110111: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd0; - imm_format = `__U_IMMIDIATE__; - end - - /* AUIPC */ - 17'b???????_???_0010111: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b1; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__U_IMMIDIATE__; - end - - /* JAL */ - 17'b???????_???_1101111: - begin - jump_en_o = 1'b1; - comparison_type_o = `__CMP_UN__; - rf_we_o = 1'b1; - rf_din_sel_o = 3'd1; - a_op_sel_o = 1'b1; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__J_IMMIDIATE__; - end - - /* JALR */ - 17'b???????_000_1100111: - begin - jump_en_o = 1'b1; - comparison_type_o = `__CMP_UN__; - rf_we_o = 1'b1; - rf_din_sel_o = 3'd1; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__I_IMMIDIATE__; - end - - /* BEQ */ - 17'b???????_000_1100011: begin - jump_en_o = 1'b1; - comparison_type_o = `__CMP_EQ__; - a_op_sel_o = 1'b1; - b_op_sel_o = 1'b1; - cmp_b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__B_IMMIDIATE__; - end - - /* BNE */ - 17'b???????_001_1100011: - begin - jump_en_o = 1'b1; - comparison_type_o = `__CMP_NQ__; - a_op_sel_o = 1'b1; - b_op_sel_o = 1'b1; - cmp_b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__B_IMMIDIATE__; - end - - /* BLT */ - 17'b???????_100_1100011: - begin - jump_en_o = 1'b1; - comparison_type_o = `__CMP_LT__; - a_op_sel_o = 1'b1; - b_op_sel_o = 1'b1; - cmp_b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__B_IMMIDIATE__; - end - - /* BGE */ - 17'b???????_101_1100011: - begin - jump_en_o = 1'b1; - comparison_type_o = `__CMP_GE__; - a_op_sel_o = 1'b1; - b_op_sel_o = 1'b1; - cmp_b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__B_IMMIDIATE__; - end - - /* BLTU */ - 17'b???????_110_1100011: - begin - jump_en_o = 1'b1; - comparison_type_o = `__CMP_LTU__; - a_op_sel_o = 1'b1; - b_op_sel_o = 1'b1; - cmp_b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__B_IMMIDIATE__; - end - - /* BGEU */ - 17'b???????_111_1100011: - begin - jump_en_o = 1'b1; - comparison_type_o = `__CMP_GEU__; - a_op_sel_o = 1'b1; - b_op_sel_o = 1'b1; - cmp_b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__B_IMMIDIATE__; - end - - /* LB, LH, LW, LBU, LHU */ - 17'b???????_???_0000011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd4; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_ADD__; - mem_we_o = 1'b0; - d_mem_load_store = 1'b1; - imm_format = `__I_IMMIDIATE__; - end - - /* SB, SH, SW */ - 17'b???????_???_0100011: - begin - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_ADD__; - mem_we_o = 1'b1; - d_mem_load_store = 1'b1; - imm_format = `__S_IMMIDIATE__; - end - - /* ADDI */ - 17'b???????_000_0010011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_ADD__; - imm_format = `__I_IMMIDIATE__; - end - - /* SLTI */ - 17'b???????_010_0010011: - begin - comparison_type_o = `__CMP_LT__; - rf_we_o = 1'b1; - rf_din_sel_o = 3'd3; - cmp_b_op_sel_o = 1'b1; - imm_format = `__I_IMMIDIATE__; - end - - /* SLTIU */ - 17'b???????_011_0010011: - begin - comparison_type_o = `__CMP_LTU__; - rf_we_o = 1'b1; - rf_din_sel_o = 3'd3; - cmp_b_op_sel_o = 1'b1; - imm_format = `__I_IMMIDIATE__; - end - - /* XORI */ - 17'b???????_100_0010011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_XOR__; - imm_format = `__I_IMMIDIATE__; - end - - /* ORI */ - 17'b???????_110_0010011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_OR__; - imm_format = `__I_IMMIDIATE__; - end - - /* ANDI */ - 17'b???????_111_0010011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_AND__; - imm_format = `__I_IMMIDIATE__; - end - - /* SLLI */ - 17'b0000000_001_0010011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_SLL__; - imm_format = `__I_IMMIDIATE__; - end - - /* SRLI */ - 17'b0000000_101_0010011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_SRL__; - imm_format = `__I_IMMIDIATE__; - end - - /* SRAI */ - 17'b0100000_101_0010011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b1; - alu_op_sel_o = `__ALU_SRA__; - imm_format = `__I_IMMIDIATE__; - end - - /* ADD */ - 17'b0000000_000_0110011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_ADD__; - end - - /* SUB */ - 17'b0100000_000_0110011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_SUB__; - end - - /* SLL */ - 17'b0000000_001_0110011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_SLL__; - end - - /* SLT */ - 17'b0000000_010_0110011: - begin - comparison_type_o = `__CMP_LT__; - rf_we_o = 1'b1; - rf_din_sel_o = 3'd3; - cmp_b_op_sel_o = 1'b0; - end - - - /* SLTU */ - 17'b0000000_011_0110011: - begin - comparison_type_o = `__CMP_LTU__; - rf_we_o = 1'b1; - rf_din_sel_o = 3'd3; - cmp_b_op_sel_o = 1'b0; - end - - /* XOR */ - 17'b0000000_100_0110011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_XOR__; - end - - /* SRL */ - 17'b0000000_101_0110011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_SRL__; - end - - /* SRA */ - 17'b0100000_101_0110011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_SRA__; - end - - /* OR */ - 17'b0000000_110_0110011:begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_OR__; - end - - /* AND */ - 17'b0000000_111_0110011: - begin - rf_we_o = 1'b1; - rf_din_sel_o = 3'd2; - a_op_sel_o = 1'b0; - b_op_sel_o = 1'b0; - alu_op_sel_o = `__ALU_AND__; - end - - ///////////////////////////////////////////////////////////////////////// - - /* CSR Instructions */ - 17'b???????_???_1110011:begin - rf_we_o = (rd_sel_o!=0); // CSR Reads should not take place if rs1 == x0 - rf_din_sel_o = 3'd5; - csru_we_o = 1; - imm_format = `__I_IMMIDIATE__; - end - - default: begin - jump_en_o = 0; - comparison_type_o = `__CMP_UN__; - rf_we_o = 0; - rf_din_sel_o = 0; - a_op_sel_o = 0; - b_op_sel_o = 0; - cmp_b_op_sel_o = 0; - alu_op_sel_o = 0; - mem_we_o = 1'b0; - imm_format = 0; - csru_we_o = 0; - - `ifdef ENABLE_RUNTIME_WARNINGS - if(opcode != 7'b1110011) // EBREAK - $display("!Unimplemented Opcode: %b", opcode); - `endif - end - - endcase -end + // Decode fields + wire [6:0] opcode = instr_i[6:0]; + wire [2:0] func3 = instr_i[14:12]; + wire [6:0] func7 = instr_i[31:25]; + + assign mem_access_width_o = func3; + assign csru_op_sel_o = func3; + + assign rd_sel_o = instr_i[11:7]; + assign rs1_sel_o = instr_i[19:15]; + assign rs2_sel_o = instr_i[24:20]; + + reg [2:0] imm_format; + + /* + Decode Immediate + */ + reg [31:0] getExtImm; + + always @(*) /*COMBINATORIAL*/ + begin + case(imm_format) + `RV_IMM_TYPE_I : getExtImm = {{21{instr_i[31]}}, instr_i[30:25], instr_i[24:21], instr_i[20]}; + `RV_IMM_TYPE_S : getExtImm = {{21{instr_i[31]}}, instr_i[30:25], instr_i[11:8], instr_i[7]}; + `RV_IMM_TYPE_B : getExtImm = {{20{instr_i[31]}}, instr_i[7], instr_i[30:25], instr_i[11:8], 1'b0}; + `RV_IMM_TYPE_U : getExtImm = {instr_i[31], instr_i[30:20], instr_i[19:12], {12{1'b0}}}; + `RV_IMM_TYPE_J : getExtImm = {{12{instr_i[31]}}, instr_i[19:12], instr_i[20], instr_i[30:25], instr_i[24:21], 1'b0}; + + default: + getExtImm = 32'd0; + endcase + end + + assign imm_o = getExtImm; + + + always @(*) begin + // DEFAULT VALUES + jump_en_o = 1'b0; + comparison_type_o = `CMP_FUNC_UN; + rf_we_o = 1'b0; + rf_din_sel_o = 3'd0; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + cmp_b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_ADD; + mem_we_o = 1'b0; + d_mem_load_store = 1'b0; + imm_format = `RV_IMM_TYPE_U; + csru_we_o = 0; + + + casez({func7, func3, opcode}) + + /* LUI */ + 17'b???????_???_0110111: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd0; + imm_format = `RV_IMM_TYPE_U; + end + + /* AUIPC */ + 17'b???????_???_0010111: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b1; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_U; + end + + /* JAL */ + 17'b???????_???_1101111: + begin + jump_en_o = 1'b1; + comparison_type_o = `CMP_FUNC_UN; + rf_we_o = 1'b1; + rf_din_sel_o = 3'd1; + a_op_sel_o = 1'b1; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_J; + end + + /* JALR */ + 17'b???????_000_1100111: + begin + jump_en_o = 1'b1; + comparison_type_o = `CMP_FUNC_UN; + rf_we_o = 1'b1; + rf_din_sel_o = 3'd1; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_I; + end + + /* BEQ */ + 17'b???????_000_1100011: begin + jump_en_o = 1'b1; + comparison_type_o = `CMP_FUNC_EQ; + a_op_sel_o = 1'b1; + b_op_sel_o = 1'b1; + cmp_b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_B; + end + + /* BNE */ + 17'b???????_001_1100011: + begin + jump_en_o = 1'b1; + comparison_type_o = `CMP_FUNC_NQ; + a_op_sel_o = 1'b1; + b_op_sel_o = 1'b1; + cmp_b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_B; + end + + /* BLT */ + 17'b???????_100_1100011: + begin + jump_en_o = 1'b1; + comparison_type_o = `CMP_FUNC_LT; + a_op_sel_o = 1'b1; + b_op_sel_o = 1'b1; + cmp_b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_B; + end + + /* BGE */ + 17'b???????_101_1100011: + begin + jump_en_o = 1'b1; + comparison_type_o = `CMP_FUNC_GE; + a_op_sel_o = 1'b1; + b_op_sel_o = 1'b1; + cmp_b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_B; + end + + /* BLTU */ + 17'b???????_110_1100011: + begin + jump_en_o = 1'b1; + comparison_type_o = `CMP_FUNC_LTU; + a_op_sel_o = 1'b1; + b_op_sel_o = 1'b1; + cmp_b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_B; + end + + /* BGEU */ + 17'b???????_111_1100011: + begin + jump_en_o = 1'b1; + comparison_type_o = `CMP_FUNC_GEU; + a_op_sel_o = 1'b1; + b_op_sel_o = 1'b1; + cmp_b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_B; + end + + /* LB, LH, LW, LBU, LHU */ + 17'b???????_???_0000011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd4; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_ADD; + mem_we_o = 1'b0; + d_mem_load_store = 1'b1; + imm_format = `RV_IMM_TYPE_I; + end + + /* SB, SH, SW */ + 17'b???????_???_0100011: + begin + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_ADD; + mem_we_o = 1'b1; + d_mem_load_store = 1'b1; + imm_format = `RV_IMM_TYPE_S; + end + + /* ADDI */ + 17'b???????_000_0010011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_ADD; + imm_format = `RV_IMM_TYPE_I; + end + + /* SLTI */ + 17'b???????_010_0010011: + begin + comparison_type_o = `CMP_FUNC_LT; + rf_we_o = 1'b1; + rf_din_sel_o = 3'd3; + cmp_b_op_sel_o = 1'b1; + imm_format = `RV_IMM_TYPE_I; + end + + /* SLTIU */ + 17'b???????_011_0010011: + begin + comparison_type_o = `CMP_FUNC_LTU; + rf_we_o = 1'b1; + rf_din_sel_o = 3'd3; + cmp_b_op_sel_o = 1'b1; + imm_format = `RV_IMM_TYPE_I; + end + + /* XORI */ + 17'b???????_100_0010011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_XOR; + imm_format = `RV_IMM_TYPE_I; + end + + /* ORI */ + 17'b???????_110_0010011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_OR; + imm_format = `RV_IMM_TYPE_I; + end + + /* ANDI */ + 17'b???????_111_0010011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_AND; + imm_format = `RV_IMM_TYPE_I; + end + + /* SLLI */ + 17'b0000000_001_0010011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_SLL; + imm_format = `RV_IMM_TYPE_I; + end + + /* SRLI */ + 17'b0000000_101_0010011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_SRL; + imm_format = `RV_IMM_TYPE_I; + end + + /* SRAI */ + 17'b0100000_101_0010011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b1; + alu_op_sel_o = `ALU_FUNC_SRA; + imm_format = `RV_IMM_TYPE_I; + end + + /* ADD */ + 17'b0000000_000_0110011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_ADD; + end + + /* SUB */ + 17'b0100000_000_0110011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_SUB; + end + + /* SLL */ + 17'b0000000_001_0110011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_SLL; + end + + /* SLT */ + 17'b0000000_010_0110011: + begin + comparison_type_o = `CMP_FUNC_LT; + rf_we_o = 1'b1; + rf_din_sel_o = 3'd3; + cmp_b_op_sel_o = 1'b0; + end + + + /* SLTU */ + 17'b0000000_011_0110011: + begin + comparison_type_o = `CMP_FUNC_LTU; + rf_we_o = 1'b1; + rf_din_sel_o = 3'd3; + cmp_b_op_sel_o = 1'b0; + end + + /* XOR */ + 17'b0000000_100_0110011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_XOR; + end + + /* SRL */ + 17'b0000000_101_0110011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_SRL; + end + + /* SRA */ + 17'b0100000_101_0110011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_SRA; + end + + /* OR */ + 17'b0000000_110_0110011:begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_OR; + end + + /* AND */ + 17'b0000000_111_0110011: + begin + rf_we_o = 1'b1; + rf_din_sel_o = 3'd2; + a_op_sel_o = 1'b0; + b_op_sel_o = 1'b0; + alu_op_sel_o = `ALU_FUNC_AND; + end + + ///////////////////////////////////////////////////////////////////////// + + /* CSR Instructions */ + 17'b???????_???_1110011:begin + rf_we_o = (rd_sel_o!=0); // CSR Reads should not take place if rs1 == x0 + rf_din_sel_o = 3'd5; + csru_we_o = 1; + imm_format = `RV_IMM_TYPE_I; + end + + default: begin + jump_en_o = 0; + comparison_type_o = `CMP_FUNC_UN; + rf_we_o = 0; + rf_din_sel_o = 0; + a_op_sel_o = 0; + b_op_sel_o = 0; + cmp_b_op_sel_o = 0; + alu_op_sel_o = 0; + mem_we_o = 1'b0; + imm_format = 0; + csru_we_o = 0; + + `ifdef verilator + if(opcode != 7'b1110011) // EBREAK + $display("!Warning: Unimplemented Opcode: %b", opcode); + `endif + end + + endcase + end endmodule \ No newline at end of file diff --git a/rtl/core/Defs.vh b/rtl/core/Defs.vh new file mode 100644 index 00000000..4eacff91 --- /dev/null +++ b/rtl/core/Defs.vh @@ -0,0 +1,68 @@ +////////////////////////////////////////////////////////////////// +// File : Defs.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : Common Definitions for Atom core +////////////////////////////////////////////////////////////////// + +`ifndef __DEFS_VH__ +`define __DEFS_VH__ + + +// Reset Address +`ifdef SOC_RESET_ADDRESS + `define RESET_PC_ADDRESS `SOC_RESET_ADDRESS +`else + // Default + `define RESET_PC_ADDRESS 32'h0000000 +`endif + + +// NOP instruction (addi x0, x0, 0) +`define RV_INSTR_NOP 32'h00000013 + + +// RISCV Immediate types +`define RV_IMM_TYPE_I 3'd0 +`define RV_IMM_TYPE_S 3'd1 +`define RV_IMM_TYPE_B 3'd2 +`define RV_IMM_TYPE_U 3'd3 +`define RV_IMM_TYPE_J 3'd4 + + +// ALU +`define ALU_FUNC_ADD 3'd0 +`define ALU_FUNC_SUB 3'd1 +`define ALU_FUNC_XOR 3'd2 +`define ALU_FUNC_OR 3'd3 +`define ALU_FUNC_AND 3'd4 +`define ALU_FUNC_SLL 3'd5 +`define ALU_FUNC_SRL 3'd6 +`define ALU_FUNC_SRA 3'd7 + + +// Comparator Unit +`define CMP_FUNC_UN 3'd0 +`define CMP_FUNC_EQ 3'd1 +`define CMP_FUNC_NQ 3'd2 +`define CMP_FUNC_LT 3'd3 +`define CMP_FUNC_GE 3'd4 +`define CMP_FUNC_LTU 3'd5 +`define CMP_FUNC_GEU 3'd6 + + +// Register File +`define RF_R0_IS_ZERO + + +// ALU +`define ALU_FUNC_ADD 3'd0 +`define ALU_FUNC_SUB 3'd1 +`define ALU_FUNC_XOR 3'd2 +`define ALU_FUNC_OR 3'd3 +`define ALU_FUNC_AND 3'd4 +`define ALU_FUNC_SLL 3'd5 +`define ALU_FUNC_SRL 3'd6 +`define ALU_FUNC_SRA 3'd7 + + +`endif // __DEFS_VH__ \ No newline at end of file diff --git a/rtl/core/RegisterFile.v b/rtl/core/RegisterFile.v index a32b2c2f..0929312a 100644 --- a/rtl/core/RegisterFile.v +++ b/rtl/core/RegisterFile.v @@ -3,70 +3,75 @@ // // File : RegisterFile.v // Author : Saurabh Singh (saurabh.s99100@gmail.com) -// Description : Parametrized register file for RISCV atom core +// Description : Parametrized register file for RISCV atom core //////////////////////////////////////////////////////////////////// -`default_nettype none `include "../Timescale.vh" +`include "Utils.vh" +`include "Defs.vh" + +`default_nettype none -module RegisterFile #( parameter REG_WIDTH = 16, parameter REG_ADDR_WIDTH = 4) -( - //////////////////// PORTLIST ///////////////////// +module RegisterFile #( + parameter REG_WIDTH = 16, + parameter REG_ADDR_WIDTH = 4 +) ( + //////////////////// PORTLIST ///////////////////// - // read port 1 (Asynchronous Read) - input wire [REG_ADDR_WIDTH-1:0] Ra_Sel_i, - output wire [REG_WIDTH-1:0] Ra_o, - - // read port 2 (Asynchronous Read) - input wire [REG_ADDR_WIDTH-1:0] Rb_Sel_i, - output wire [REG_WIDTH-1:0] Rb_o, + // read port 1 (Asynchronous Read) + input wire [REG_ADDR_WIDTH-1:0] Ra_Sel_i, + output wire [REG_WIDTH-1:0] Ra_o, + + // read port 2 (Asynchronous Read) + input wire [REG_ADDR_WIDTH-1:0] Rb_Sel_i, + output wire [REG_WIDTH-1:0] Rb_o, - // write port (Synchronous Write) - input wire Data_We_i, - input wire [REG_ADDR_WIDTH-1:0] Rd_Sel_i, - input wire [REG_WIDTH-1:0] Data_i, + // write port (Synchronous Write) + input wire Data_We_i, + input wire [REG_ADDR_WIDTH-1:0] Rd_Sel_i, + input wire [REG_WIDTH-1:0] Data_i, - input wire Clk_i, - input wire Rst_i + input wire Clk_i, + input wire Rst_i ); - localparam REG_COUNT = 2**REG_ADDR_WIDTH; + localparam REG_COUNT = 2**REG_ADDR_WIDTH; - `ifdef __R0_IS_ZERO__ - reg [REG_WIDTH-1:0] regs [1:REG_COUNT-1] /*verilator public*/; // register array - `else - reg [REG_WIDTH-1:0] regs [0:REG_COUNT-1] /*verilator public*/; // register array - `endif - - integer i; + `ifdef RF_R0_IS_ZERO + reg [REG_WIDTH-1:0] regs [1:REG_COUNT-1] /*verilator public*/; // register array + `else + reg [REG_WIDTH-1:0] regs [0:REG_COUNT-1] /*verilator public*/; // register array + `endif + + integer i; - /* === WRITE PORT === - Synchronous write - */ - always @ (posedge Clk_i) begin - if (Rst_i) begin - for(i=1; i (y)) ? (x) : (y)) + + +///////////////////////////////////////////////////////////// +// Macros for Verilator + +`define TRACING_ON /* verilator tracing_on */ + +`define TRACING_OFF /* verilator tracing_off */ + +`define UNUSED_VAR(x) always @(x) begin end + +`define UNUSED_PARAM(x) /* verilator lint_off UNUSED */ \ + localparam __``x = x; \ + /* verilator lint_on UNUSED */ + +`define UNUSED_PIN(x) /* verilator lint_off PINCONNECTEMPTY */ \ + . x () \ + /* verilator lint_on PINCONNECTEMPTY */ + +`define ASSERT(cond, msg) \ + assert(cond) else $error msg + +`endif // __UTILS_H__ diff --git a/rtl/uncore/BiDirectionalIO.v b/rtl/uncore/BiDirectionalIO.v index a37ce20c..d6ce33dc 100644 --- a/rtl/uncore/BiDirectionalIO.v +++ b/rtl/uncore/BiDirectionalIO.v @@ -1,3 +1,9 @@ +//////////////////////////////////////////////////////////////////// +// File : BiDirectionalIO.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : BiDirectional IO (for GPIO pins) +//////////////////////////////////////////////////////////////////// + `default_nettype none module BiDirectionalIO diff --git a/rtl/uncore/DualPortRAM_wb.v b/rtl/uncore/DualPortRAM_wb.v index 5bc25663..917bb9ce 100644 --- a/rtl/uncore/DualPortRAM_wb.v +++ b/rtl/uncore/DualPortRAM_wb.v @@ -1,3 +1,10 @@ +//////////////////////////////////////////////////////////////////// +// File : DualPortRAM.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : A Wishbone interfaced RAM with two ports, Port 1 +// is a Read/Write port while, Port 2 is a readonly port +//////////////////////////////////////////////////////////////////// + `default_nettype none module DualPortRAM_wb #( diff --git a/rtl/uncore/GPIO.v b/rtl/uncore/GPIO.v index 65b81087..b5d58faf 100644 --- a/rtl/uncore/GPIO.v +++ b/rtl/uncore/GPIO.v @@ -1,3 +1,22 @@ +//////////////////////////////////////////////////////////////////// +// File : GPIO.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : GPIO module is a wishbone controlled peripheral +// which contains 16 Gpio pins (Bi-Directional) +// +// Control register | width | relative address +// ------------------|-------------|------------------- +// gpio_state 2 bytes 0x00000000 +// gpio_direction 2 bytes 0x00000002 +// +// each bit in the registers directly corresponds to an io pin. +// writing "1" to a bit in gpio_direction configures that pin as +// an input, while writing "0" configures it as an output. +// Similarily, writing "1" in gpio_state set a pin "HIGH" while +// writing "0" sets it "LOW". +// +//////////////////////////////////////////////////////////////////// + `include "BiDirectionalIO.v" `default_nettype none @@ -10,9 +29,7 @@ module GPIO output reg [31:0] wb_dat_o, - /* verilator lint_off UNUSED */ input wire [31:0] wb_dat_i, - /* verilator lint_on UNUSED */ input wire wb_we_i, input wire [3:0] wb_sel_i, diff --git a/rtl/uncore/SinglePortRAM_wb.v b/rtl/uncore/SinglePortRAM_wb.v index 7146299d..0fed0b49 100644 --- a/rtl/uncore/SinglePortRAM_wb.v +++ b/rtl/uncore/SinglePortRAM_wb.v @@ -1,3 +1,9 @@ +//////////////////////////////////////////////////////////////////// +// File : SinglePortRAM.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : A Wishbone interfaced RAM with single Read/Write port +//////////////////////////////////////////////////////////////////// + `default_nettype none module SinglePortRAM_wb #( diff --git a/rtl/uncore/SinglePortROM_wb.v b/rtl/uncore/SinglePortROM_wb.v index a3e556db..0276d0b8 100644 --- a/rtl/uncore/SinglePortROM_wb.v +++ b/rtl/uncore/SinglePortROM_wb.v @@ -1,3 +1,8 @@ +//////////////////////////////////////////////////////////////////// +// File : SinglePortROM.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : A Wishbone interfaced ROM module +//////////////////////////////////////////////////////////////////// `default_nettype none module SinglePortROM_wb #( diff --git a/rtl/uncore/simpleuart_wb.v b/rtl/uncore/simpleuart_wb.v index 86611556..63828db2 100644 --- a/rtl/uncore/simpleuart_wb.v +++ b/rtl/uncore/simpleuart_wb.v @@ -1,3 +1,29 @@ +//////////////////////////////////////////////////////////////////// +// File : simpleuart_wb.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : Wishbone wrapper for simpleuart.v by clifford wolf +// +// Register Description +// --------------------- +// +// let base address = 0x00000000 +// +// 0x00000000 : 8-bit data register (D-Reg) [ Read & Write ] +// To transmit a byte : Write to this register +// To get recieved value : Read from this register. +// if no value is recieved or value is already read then reg will contain -1. +// +// 0x00000001 : 8-bit status (S-Reg) [ Read Only ] +// bit[0] = recv_buf_valid : recieve buffer has a valid value +// bit[1] = tx_busy : Transmitter is busy transmitting a byte +// +// 0x00000004 : 32-bit Clock Divider Register (CD-Reg) [ Read & Write ] +// CD register sets the speed of uart tx & rx. +// if your clk freq is Fc and target baud frequency is Fb then formula for correct value +// of CD reg is: +// value = (Fc / Fb) - 2; +// +//////////////////////////////////////////////////////////////////// `default_nettype none `include "simpleuart.v" @@ -27,29 +53,6 @@ module simpleuart_wb /* verilator lint_on UNDRIVEN */ ); //////////////////////////////////////////////////////////////////////////////////////////////////// -/* - Register Description - --------------------- - - let base address = 0x00000000 - - 0x00000000 : 8-bit data register (D-Reg) [ Read & Write ] - To transmit a byte : Write to this register - To get recieved value : Read from this register. - if no value is recieved or value is already read then reg will contain -1. - - 0x00000001 : 8-bit status (S-Reg) [ Read Only ] - bit[0] = recv_buf_valid : recieve buffer has a valid value - bit[1] = tx_busy : Transmitter is busy transmitting a byte - - 0x00000004 : 32-bit Clock Divider Register (CD-Reg) [ Read & Write ] - CD register sets the speed of uart tx & rx. - if your clk freq is Fc and target baud frequency is Fb then formula for correct value - of CD reg is: - value = (Fc / Fb) - 2; -*/ - - /* if __ATOMSIM_SIMULATION__ is defined, this module behaves as a stub. simpleuart is not instantiated, instead reg_status, reg_data, and reg_div are converted to actual registers diff --git a/sourceme b/sourceme new file mode 100644 index 00000000..6547bf4b --- /dev/null +++ b/sourceme @@ -0,0 +1,10 @@ +## RISCV-ATOM Environment Variabes + +# export RVATOM variable +export RVATOM="/home/${USER}/work/riscv/riscv-atom" + +# add $RVATOM/build/bin to path +export PATH="$RVATOM/build/bin:$PATH" + +# export RVATOM_LIBS variable +export RVATOM_LIB="$RVATOM/sw/lib" \ No newline at end of file diff --git a/sw/examples/dining-phil/Makefile.include b/sw/examples/dining-phil/Makefile.include new file mode 100644 index 00000000..f3243501 --- /dev/null +++ b/sw/examples/dining-phil/Makefile.include @@ -0,0 +1,2 @@ +src_files = dining-phil.c +executable = dining-phil.elf \ No newline at end of file diff --git a/sw/examples/dining-phil/dining-phil.c b/sw/examples/dining-phil/dining-phil.c new file mode 100644 index 00000000..26da71d7 --- /dev/null +++ b/sw/examples/dining-phil/dining-phil.c @@ -0,0 +1,128 @@ +// @see https://www.thecrazyprogrammer.com/2017/06/dining-philosophers-problem-c-c.html + +#include + +#define n 4 + +int compltedPhilo = 0, i; + +struct fork +{ + int taken; +} ForkAvil[n]; + +struct philosp +{ + int left; + int right; +} Philostatus[n]; + + + +void goForDinner(int philID) +{ + if(Philostatus[philID].left==10 && Philostatus[philID].right == 10) // same like threads concept here cases implemented + { + printf("Philosopher %d completed his dinner\n", philID + 1); + } + else if(Philostatus[philID].left==1 && Philostatus[philID].right == 1) // if already completed dinner + { + printf("Philosopher %d completed his dinner\n", philID + 1); // if just taken two forks + + Philostatus[philID].left = Philostatus[philID].right = 10; // remembering that he completed dinner by assigning value 10 + int otherFork = philID - 1; + + if(otherFork == -1) + otherFork = (n-1); + + ForkAvil[philID].taken = ForkAvil[otherFork].taken = 0; // releasing forks + printf("Philosopher %d released fork %d and fork %d\n", philID+1, philID+1, otherFork+1); + compltedPhilo++; + } + else if(Philostatus[philID].left==1 && Philostatus[philID].right == 0) + { + if(philID==(n-1)) //left already taken, trying for right fork + { + if(ForkAvil[philID].taken==0) // KEY POINT OF THIS PROBLEM, THAT LAST PHILOSOPHER TRYING IN reverse DIRECTION + { + ForkAvil[philID].taken = Philostatus[philID].right = 1; + printf("Fork %d taken by philosopher %d\n",philID+1,philID+1); + } + else + { + printf("Philosopher %d is waiting for fork %d\n",philID+1,philID+1); + } + } + else + { + //except last philosopher case + int dupphilID = philID; + philID-=1; + + if(philID== -1) + philID=(n-1); + + if(ForkAvil[philID].taken == 0) + { + ForkAvil[philID].taken = Philostatus[dupphilID].right = 1; + printf("Fork %d taken by Philosopher %d\n",philID+1,dupphilID+1); + } + else + { + printf("Philosopher %d is waiting for Fork %d\n",dupphilID+1,philID+1); + } + } + } + else if(Philostatus[philID].left==0) + { + //nothing taken yet + if(philID==(n-1)) + { + if(ForkAvil[philID-1].taken==0) + { + //KEY POINT OF THIS PROBLEM, THAT LAST PHILOSOPHER TRYING IN reverse DIRECTION + ForkAvil[philID-1].taken = Philostatus[philID].left = 1; + printf("Fork %d taken by philosopher %d\n",philID,philID+1); + } + else + { + printf("Philosopher %d is waiting for fork %d\n",philID+1,philID); + } + } + else + { + //except last philosopher case + if(ForkAvil[philID].taken == 0) + { + ForkAvil[philID].taken = Philostatus[philID].left = 1; + printf("Fork %d taken by Philosopher %d\n",philID+1,philID+1); + } + else + { + printf("Philosopher %d is waiting for Fork %d\n",philID+1,philID+1); + } + } + } + else + {} +} + + +int main() +{ + for(i=0; i> Till now num of philosophers completed dinner are %d\n\n",compltedPhilo); + } + return 0; +} diff --git a/test/riscv-target/atombones/model_test.h b/test/riscv-target/atombones/model_test.h index 5e4a2096..41c81072 100644 --- a/test/riscv-target/atombones/model_test.h +++ b/test/riscv-target/atombones/model_test.h @@ -11,7 +11,7 @@ .align 8; .global end_regstate; end_regstate: \ .word 4; -#include "../../../sw/lib/atombones.h" +// #include "../../../sw/lib/atombones.h" //TODO: Add code here to run after all tests have been run // The .align 4 ensures that the signature begins at a 16-byte boundary diff --git a/test/riscv-target/hydrogensoc/model_test.h b/test/riscv-target/hydrogensoc/model_test.h index 5e4a2096..41c81072 100644 --- a/test/riscv-target/hydrogensoc/model_test.h +++ b/test/riscv-target/hydrogensoc/model_test.h @@ -11,7 +11,7 @@ .align 8; .global end_regstate; end_regstate: \ .word 4; -#include "../../../sw/lib/atombones.h" +// #include "../../../sw/lib/atombones.h" //TODO: Add code here to run after all tests have been run // The .align 4 ensures that the signature begins at a 16-byte boundary