Skip to content

Fetch stage #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.vvp
*.vcd

.devcontainer/
17 changes: 9 additions & 8 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -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)
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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
Empty file added out/.gitkeep
Empty file.
2 changes: 1 addition & 1 deletion src/Instruction_Decode/Instruction_Decode.v
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
36 changes: 36 additions & 0 deletions src/fetch.sv
Original file line number Diff line number Diff line change
@@ -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
10 changes: 5 additions & 5 deletions src/params.vh
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
45 changes: 45 additions & 0 deletions src/top.v
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions src/types.svh
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions src/utils.svh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
`ifndef UTILS_VH
`define UTILS_VH

`define TRUE 1'b1
`define FALSE 1'b0

`endif
19 changes: 19 additions & 0 deletions src/utils/MA.v
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions src/utils/adder.sv
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WIDTH parameter might need to be specified at the declaration line

Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions src/utils/register.sv
Original file line number Diff line number Diff line change
@@ -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
145 changes: 145 additions & 0 deletions test/fetch_tb.sv
Original file line number Diff line number Diff line change
@@ -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