diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb21ac5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.vvp +*.vcd + +.devcontainer/ diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ba9b207..fec7843 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,8 +1,9 @@ -Project Contributors: -Reece L-M (Eridarus) -James Kim (jamesjhkim) -Harsh Grover (hgrover19) -Yuxuan Seah -Edward Wu (edwu0029) -Brett(Jiaxin) Yang (brettyang02) -Joonseo Park (joon2022park) +Project Contributors: +Reece L-M (Eridarus) +James Kim (jamesjhkim) +Harsh Grover (hgrover19) +Yuxuan Seah +Edward Wu (edwu0029) +Brett(Jiaxin) Yang (brettyang02) +Joonseo Park (joon2022park) +Boris Potapov (TheDeepestSpace) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..44897d3 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +SRC_DIR := src +SRCS := $(shell find $(SRC_DIR) -type f \( -name "*.sv" -o -name "*.svh" -o -name "*.v" -o -name "*.vh" \)) +OUTPUT := out/top.vvp +IVERILOG := iverilog +VVP := vvp + +all: $(OUTPUT) + +$(OUTPUT): $(SRCS) + $(IVERILOG) -g2012 -o $(OUTPUT) $(SRCS) + +run: $(OUTPUT) + $(VVP) $(OUTPUT) + +# tmp +fetch_tb: + $(IVERILOG) -g2012 -o $(OUTPUT) $(SRCS) test/fetch_tb.sv + +.PHONY: all run diff --git a/out/.gitkeep b/out/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Instruction_Decode/Instruction_Decode.v b/src/Instruction_Decode/Instruction_Decode.v index 0b765d7..48923a1 100644 --- a/src/Instruction_Decode/Instruction_Decode.v +++ b/src/Instruction_Decode/Instruction_Decode.v @@ -24,7 +24,7 @@ module Instruction_Decode( wire [2:0] ALUOp; //wire from Control FSM to ALU Decoder wire RegWrite; reg [2:0] funct3; - reg [6:0] funct7 + reg [6:0] funct7; reg [4:0] rd, rs1, rs2; wire [3:0] state; diff --git a/src/fetch.sv b/src/fetch.sv new file mode 100644 index 0000000..98a4d39 --- /dev/null +++ b/src/fetch.sv @@ -0,0 +1,36 @@ +/* sandbox module for fetching instructions */ + +`include "src/utils.svh" +`include "src/types.svh" + +module fetch ( input wire clk + , input wire reset + , input wire cfsm__pc_update + , output instr_t instr + ); + + addr_t pc_next, pc_cur; + + register #( .DATA_TYPE( addr_t ) ) program_counter + ( .clk ( clk ) + , .reset ( reset ) + , .en ( cfsm__pc_update ) + , .data_in ( pc_next ) + , .data_out ( pc_cur ) + ); + + adder #( .WIDTH( `PROCESSOR_BITNESS ) ) program_counter_plus_4 + ( .lhs ( pc_cur ) + , .rhs ( 32'h4 ) + , .out ( pc_next ) + ); + + MA instruction_memory + ( .A ( pc_cur ) + , .WD ( 32'hxxxxxxxx ) + , .WE ( `FALSE ) + , .CLK ( clk ) + , .RD ( instr ) + ); + +endmodule diff --git a/src/params.vh b/src/params.vh index 7eefee7..4051183 100644 --- a/src/params.vh +++ b/src/params.vh @@ -3,7 +3,7 @@ //Opcodes parameter RType = 7'b0110011; -parameter IType = 7'b0010011; //excluding lw +parameter IType = 7'b0010011; //excluding lw parameter LWType = 7'b0000011; parameter SType = 7'b0100011; parameter BType = 7'b1100011; @@ -12,13 +12,13 @@ parameter JType = 7'b1101111; //ALU Operation Control Codes parameter ALUAdd = 4'b0000; parameter ALUSub = 4'b0001; -parameter ALUSLL = 4'b0010; +parameter ALUSLL = 4'b0010; parameter ALUSLT = 4'b0011; -parameter ALUSLTU = = 4'b0100; +parameter ALUSLTU = = 4'b0100; parameter ALUXOR = 4'b0101; -parameter ALUSRL = 4'b0110; +parameter ALUSRL = 4'b0110; parameter ALUSRA = 4'b0111; -parameter ALUOR = 4'b1000; +parameter ALUOR = 4'b1000; parameter ALUAND = 4'b1001; `endif // PARAMS_VH diff --git a/src/top.v b/src/top.v index e69de29..a7d046e 100644 --- a/src/top.v +++ b/src/top.v @@ -0,0 +1,45 @@ +`include "src/types.svh" + +module top ( input wire clk + , input wire reset + ); + + wire cfsm__pc_update; + instr_t instr; + + wire __tmp_AdrSrc + , __tmp_IRWrite + , __tmp_RegWrite + , __tmp_MemWrite + , __tmp_Branch; + wire [1:0] __tmp_ALUSrcA + , __tmp_ALUSrcB; + wire [2:0] __tmp_ALUOp; + wire [1:0] __tmp_ResultSrc; + wire [3:0] __tmp_FSMState; + + ControlFSM control_fsm + ( .opcode ( 7'b0000000 ) + , .clk ( clk ) + , .reset ( reset ) + , .AdrSrc ( __tmp_AdrSrc ) + , .IRWrite ( __tmp_IRWrite ) + , .RegWrite ( __tmp_RegWrite ) + , .PCUpdate ( cfsm__pc_update ) + , .MemWrite ( __tmp_MemWrite ) + , .Branch ( __tmp_Branch ) + , .ALUSrcA ( __tmp_ALUSrcA ) + , .ALUSrcB ( __tmp_ALUSrcB ) + , .ALUOp ( __tmp_ALUOp ) + , .ResultSrc ( __tmp_ResultSrc ) + , .FSMState ( __tmp_FSMState ) + ); + + fetch fetch + ( .clk ( clk ) + , .reset ( reset ) + , .cfsm__pc_update ( cfsm__pc_update ) + , .instr ( instr ) + ); + +endmodule diff --git a/src/types.svh b/src/types.svh new file mode 100644 index 0000000..9958356 --- /dev/null +++ b/src/types.svh @@ -0,0 +1,10 @@ +`ifndef TYPES_VH +`define TYPES_VH + +/* defines the bitness of the processor */ +`define PROCESSOR_BITNESS 32 + +typedef logic [`PROCESSOR_BITNESS-1:0] instr_t; +typedef logic [`PROCESSOR_BITNESS-1:0] addr_t; + +`endif diff --git a/src/utils.svh b/src/utils.svh new file mode 100644 index 0000000..b3f65d4 --- /dev/null +++ b/src/utils.svh @@ -0,0 +1,7 @@ +`ifndef UTILS_VH +`define UTILS_VH + +`define TRUE 1'b1 +`define FALSE 1'b0 + +`endif diff --git a/src/utils/MA.v b/src/utils/MA.v new file mode 100644 index 0000000..f29379e --- /dev/null +++ b/src/utils/MA.v @@ -0,0 +1,19 @@ +module MA #( parameter SIZE = 1024 ) + ( input [31:0] A + , input [31:0] WD + , input WE + , input CLK + , output [31:0] RD + ); + + reg [31:0] M[0:SIZE-1]; + + assign RD = M[A[31:2]]; // 2 LSBs used for byte addressing + + always @(posedge CLK) begin + if (WE) begin + M[A[31:2]] <= WD; + end + end + +endmodule diff --git a/src/utils/adder.sv b/src/utils/adder.sv new file mode 100644 index 0000000..5d860ce --- /dev/null +++ b/src/utils/adder.sv @@ -0,0 +1,15 @@ +/* generic adder module */ + +`include "src/utils.svh" + +module adder #( parameter WIDTH + ) + ( input wire [WIDTH-1:0] lhs + , input wire [WIDTH-1:0] rhs + , output reg [WIDTH-1:0] out + ); + + always @(*) begin + out <= lhs + rhs; + end +endmodule diff --git a/src/utils/register.sv b/src/utils/register.sv new file mode 100644 index 0000000..be82a0e --- /dev/null +++ b/src/utils/register.sv @@ -0,0 +1,21 @@ +/* Generic register module */ + +module register #( type DATA_TYPE + ) + ( input wire clk + , input wire reset + , input wire en + , input wire [31:0] data_in + , output reg [31:0] data_out + ); + + always @(posedge clk) begin + if (reset) begin + data_out <= 32'b0; + end + else + if (en) begin + data_out <= data_in; + end + end +endmodule diff --git a/test/fetch_tb.sv b/test/fetch_tb.sv new file mode 100644 index 0000000..55b0207 --- /dev/null +++ b/test/fetch_tb.sv @@ -0,0 +1,145 @@ +`timescale 1ns/1ps + +`include "src/utils.svh" + +module fetch_tb; + + reg clk; + reg reset; + reg cfsm__pc_update; + instr_t instr; + + fetch uut + ( .clk ( clk ) + , .reset ( reset ) + , .cfsm__pc_update ( cfsm__pc_update ) + , .instr ( instr ) + ); + + initial begin + clk = 0; + forever #5 clk = ~clk; + end + + initial begin + cfsm__pc_update <= `FALSE; + + assert(uut.pc_cur === 32'hxxxxxxxx) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'hxxxxxxxx) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hxxxxxxxx) else $error("`instr` is `%0h`", instr); + + reset <= `TRUE; + #10; + reset <= `FALSE; + + // pc is set at the start + assert(uut.pc_cur === 32'h00000000) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000004) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + // instruction is unknown since memory is not initialized + assert(instr === 32'hxxxxxxxx) else $error("`instr` is `%0h`", instr); + + #10; + + // pc_cur has not changed since we need pc_update to be set + assert(uut.pc_cur === 32'h00000000) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000004) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + + cfsm__pc_update <= `TRUE; + + #10; + + // pc_cur is updated + assert(uut.pc_cur === 32'h00000004) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + // pc_next is incremented + assert(uut.pc_next === 32'h00000008) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + + cfsm__pc_update <= `FALSE; + + #10; + + // pc_cur and pc_next are the same + assert(uut.pc_cur === 32'h00000004) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000008) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + + // initialize memory + uut.instruction_memory.M[0] = 32'h11223344; + uut.instruction_memory.M[1] = 32'h55667788; + uut.instruction_memory.M[2] = 32'h99aabbcc; + uut.instruction_memory.M[3] = 32'hddeeff00; + + for (int i = 4; i < 1020; i = i + 1) begin + uut.instruction_memory.M[i] = 32'h00000000; + end + + uut.instruction_memory.M[1020] = 32'hdeadbeef; + uut.instruction_memory.M[1021] = 32'hfeedface; + uut.instruction_memory.M[1022] = 32'hcafebabe; + uut.instruction_memory.M[1023] = 32'hf00dcafe; + + reset <= `TRUE; + #10; + reset <= `FALSE; + + assert(uut.pc_cur === 32'h00000000) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000004) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'h11223344) else $error("`instr` is `%0h`", instr); + + // request another instruction + cfsm__pc_update <= `TRUE; + #10; + + assert(uut.pc_cur === 32'h00000004) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000008) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'h55667788) else $error("`instr` is `%0h`", instr); + + #10; + + assert(uut.pc_cur === 32'h00000008) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h0000000c) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'h99aabbcc) else $error("`instr` is `%0h`", instr); + + #10; + + assert(uut.pc_cur === 32'h0000000c) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000010) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hddeeff00) else $error("`instr` is `%0h`", instr); + + #10170; + + assert(uut.pc_cur === 32'h00000ff0) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000ff4) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hdeadbeef) else $error("`instr` is `%0h`", instr); + + #10; + + assert(uut.pc_cur === 32'h00000ff4) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000ff8) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hfeedface) else $error("`instr` is `%0h`", instr); + + #10; + + assert(uut.pc_cur === 32'h00000ff8) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000ffc) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hcafebabe) else $error("`instr` is `%0h`", instr); + + #10; + + assert(uut.pc_cur === 32'h00000ffc) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00001000) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hf00dcafe) else $error("`instr` is `%0h`", instr); + + #10; + + // out of memory + assert(uut.pc_cur === 32'h00001000) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00001004) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hxxxxxxxx) else $error("`instr` is `%0h`", instr); + + $finish; + end + + initial begin + $dumpfile("fetch_tb.vcd"); + $dumpvars(0, fetch_tb); + end +endmodule