diff --git a/Makefile b/Makefile index 44897d3..22d86fc 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,4 @@ 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 @@ -7,13 +6,13 @@ VVP := vvp all: $(OUTPUT) $(OUTPUT): $(SRCS) - $(IVERILOG) -g2012 -o $(OUTPUT) $(SRCS) + $(IVERILOG) -g2012 -o $(OUTPUT) -c src/top.cf run: $(OUTPUT) $(VVP) $(OUTPUT) # tmp fetch_tb: - $(IVERILOG) -g2012 -o $(OUTPUT) $(SRCS) test/fetch_tb.sv + $(IVERILOG) -g2012 -o $(OUTPUT) $(SRCS) -c src/top.cf test/fetch_tb.sv .PHONY: all run diff --git a/src/ControlFSM.v b/src/ControlFSM.v index ba4e972..52aefd8 100644 --- a/src/ControlFSM.v +++ b/src/ControlFSM.v @@ -33,180 +33,180 @@ module ControlFSM( parameter MEMREAD = 4'b1000; parameter MEMWB = 4'b1001; parameter BRANCHIFEQ = 4'b1010; - + //declare state registers reg [3:0] current_state, next_state; - + //Next state logic always@(*)begin - + case(current_state) - + FETCH: next_state = DECODE; - + DECODE: begin - - if (opcode == 7'b1101111) next_state = UNCONDJUMP; - + + if (opcode == JType) next_state = UNCONDJUMP; + else if (opcode == 7'b0110011) next_state = EXECUTER; - + else if (opcode == 7'b0010011) next_state = EXECUTEI; - + else if (opcode == 7'b0000011 || opcode == 7'b0100011) next_state = MEMADR; - + else if (opcode == 7'b1100011) next_state = BRANCHIFEQ; - + else next_state = DECODE; - + end - + UNCONDJUMP: next_state = ALUWB; - + EXECUTER: next_state = ALUWB; - + EXECUTEI: next_state = ALUWB; - + MEMADR: begin - + if (opcode == 7'b0000011) next_state = MEMREAD; - + else if (opcode == 7'b0100011) next_state = MEMWRITE; - + else next_state = MEMADR; - + end - + BRANCHIFEQ: next_state = FETCH; - + ALUWB: next_state = FETCH; - + MEMREAD: next_state = MEMWB; - + MEMWRITE: next_state = FETCH; - + MEMWB: next_state = FETCH; - + default: next_state = FETCH; - + endcase - + end - + //output logic always@(posedge clk) begin - + FSMState <= current_state; - - case(current_state) - + + case(current_state) + FETCH: begin - + AdrSrc <= 1'b0; IRWrite <= 1'b1; - + end - + DECODE: begin - + ALUSrcA <= 2'b01; ALUSrcB <= 2'b01; ALUOp <= 2'b00; - + end - + EXECUTER: begin - + ALUSrcA <= 2'b10; ALUSrcB <= 2'b00; ALUOp <= 2'b10; - + end - + EXECUTEI: begin - + ALUSrcA <= 2'b10; ALUSrcB <= 2'b01; ALUOp <= 2'b10; - + end - + UNCONDJUMP: begin - + ALUSrcA <= 2'b01; ALUSrcB <= 2'b10; ALUOp <= 2'b00; ResultSrc <= 2'b00; PCUpdate <= 1'b1; - + end - + MEMADR: begin - + ALUSrcA <= 2'b10; ALUSrcB <= 2'b01; - ALUOp <= 2'b00; - + ALUOp <= 2'b00; + end - + BRANCHIFEQ: begin - + ALUSrcA <= 2'b10; ALUSrcB <= 2'b00; ALUOp <= 2'b01; ResultSrc <= 2'b00; Branch <= 1'b1; - + end - + ALUWB: begin - + ResultSrc <= 2'b00; RegWrite <= 1'b1; - + end - + MEMWRITE: begin - + ResultSrc <= 2'b00; AdrSrc <= 1'b1; MemWrite <= 1'b1; - + end - + MEMREAD: begin - + ResultSrc <= 2'b00; AdrSrc <= 1'b1; - + end - + MEMWB: begin - + ResultSrc <= 2'b01; RegWrite <= 1'b1; - + end - + default: begin //by default, we return to FETCH state - + AdrSrc <= 1'b0; IRWrite <= 1'b1; - + end - - + + endcase - + end - + //State transition logic (sequential) always @ (posedge clk) begin - + if (reset) current_state <= FETCH; - + else current_state <= next_state; - + end - + endmodule diff --git a/src/Instruction_Decode/Instruction_Decode.v b/src/Instruction_Decode/Instruction_Decode.v index 50c7bed..946f71f 100644 --- a/src/Instruction_Decode/Instruction_Decode.v +++ b/src/Instruction_Decode/Instruction_Decode.v @@ -1,5 +1,5 @@ -`include "params.vh" -module Instruction_Decode( +`include "src/params.vh" +module Instruction_Decode( input wire [31:0] instr, input wire clk, @@ -14,95 +14,95 @@ module Instruction_Decode( output wire [1:0] ALUSrcA, output wire [1:0] ALUSrcB, output wire [1:0] ResultSrc, - output wire [2:0] ALUControl, + output wire [3:0] ALUControl, output wire [31:0] baseAddr, output wire [31:0] writeData - + ); reg [31:0] ImmExt; - wire [2:0] ALUOp; //wire from Control FSM to ALU Decoder + wire [1:0] ALUOp; //wire from Control FSM to ALU Decoder wire RegWrite; reg [2:0] funct3; reg [6:0] funct7; reg [4:0] rd, rs1, rs2; wire [3:0] state; - + //combinational logic for extracting funct3 and funct7[5] for ALU Decoder input always@(*) begin - + if (instr[6:0] == RType) begin //R-Type - + funct3 = instr[14:12]; funct7 = instr[31:25]; - + end - + else if (instr[6:0] == IType) begin //I-Type (excluding lw) - + funct3 = instr[14:12]; funct7 = 7'b0; - + end - + else begin //lw, sw, jal, and beq instructions: - + funct3 = 3'b000; funct7 = 7'b0; - + end - + end - + //logic for extracting rs1, rs2, and rd registers from 32-bit instruction field //The logic depends on the instruction type always@(*) begin - + if (instr[6:0] == RType) begin //R-Type - + rd = instr[11:7]; rs1 = instr[19:15]; rs2 = instr[24:20]; - + end - + else if (instr[6:0] == IType || instr[6:0] == LWType) begin //I-Type (where lw is I type) - + rd = instr[11:7]; rs1 = instr[19:15]; rs2 = 5'b00000; - + end - + else if (instr[6:0] == SType || instr[6:0] == BType) begin //S-type and B-Type - + rd = 5'b00000; rs1 = instr[19:15]; rs2 = instr[24:20]; - + end - + else if (instr[6:0] == JType) begin //J-Type - + rd = instr[11:7]; rs1 = 5'b00000; rs2 = 5'b00000; - + end - + else begin - + rd = 5'b00000; rs1 = 5'b00000; rs2 = 5'b00000; - + end - + end - + //case statement for choosing 32-bit immediate format; based on opcode always@(*) begin - case(instr[6:0]) + case(instr[6:0]) IType : ImmExt = {{20{instr[31]}}, instr[31:20]}; //I-Type LWType : ImmExt = {{20{instr[31]}}, instr[31:20]}; //lw @@ -114,18 +114,19 @@ module Instruction_Decode( end //Instantiate ALU Decoder module - + ALUdecoder instanceALUDec( - + .funct3(funct3), .funct7(funct7), - .alu_op(ALUControl) - + .alu_op(ALUOp), + .alu_control(ALUControl), + ); //instantiate Register File module registerFile instanceRegFile( - + .Addr1(rs1), .Addr2(rs2), .Addr3(rd), @@ -134,7 +135,7 @@ module Instruction_Decode( .dataIn(ResultData), .baseAddr(baseAddr), .writeData(writeData) - + ); endmodule diff --git a/src/extend.sv b/src/extend.sv new file mode 100644 index 0000000..f8d14a2 --- /dev/null +++ b/src/extend.sv @@ -0,0 +1,9 @@ +// dummy extend module + +`include "src/types.svh" + +module extend ( input wire [11:0] in + , output imm_t imm_ext + ); + assign imm_ext = {{20{in[11]}}, in}; +endmodule diff --git a/src/fetch.sv b/src/fetch.sv index 98a4d39..b72b996 100644 --- a/src/fetch.sv +++ b/src/fetch.sv @@ -6,10 +6,12 @@ module fetch ( input wire clk , input wire reset , input wire cfsm__pc_update + , input wire cfsm__pc_src + , input imm_t imm_ext , output instr_t instr ); - addr_t pc_next, pc_cur; + addr_t pc_plus_4, pc_target, pc_next, pc_cur; register #( .DATA_TYPE( addr_t ) ) program_counter ( .clk ( clk ) @@ -22,7 +24,7 @@ module fetch ( input wire clk adder #( .WIDTH( `PROCESSOR_BITNESS ) ) program_counter_plus_4 ( .lhs ( pc_cur ) , .rhs ( 32'h4 ) - , .out ( pc_next ) + , .out ( pc_plus_4 ) ); MA instruction_memory @@ -33,4 +35,20 @@ module fetch ( input wire clk , .RD ( instr ) ); + adder #( .WIDTH( `PROCESSOR_BITNESS ) ) program_counter_target + ( .lhs ( pc_cur ) + , .rhs ( imm_ext ) + , .out ( pc_target ) + ); + + // Continuous assignment of array concatenation is not yet supported. + addr_t pc_mux_in [1:0]; + assign pc_mux_in[0] = pc_target; + assign pc_mux_in[1] = pc_plus_4; + mux #( .INPUT_COUNT ( 2 ), .INPUT_WIDTH ( `PROCESSOR_BITNESS ) ) pc_mux + ( .sel ( cfsm__pc_src ) + , .in ( pc_mux_in ) + , .out ( pc_next ) + ); + endmodule diff --git a/src/params.vh b/src/params.vh index 4051183..f7b617e 100644 --- a/src/params.vh +++ b/src/params.vh @@ -14,7 +14,7 @@ parameter ALUAdd = 4'b0000; parameter ALUSub = 4'b0001; 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 ALUSRA = 4'b0111; diff --git a/src/top.cf b/src/top.cf new file mode 100644 index 0000000..1dac9e9 --- /dev/null +++ b/src/top.cf @@ -0,0 +1,12 @@ +src/utils/adder.sv +src/utils/MA.v +src/utils/mux.sv +src/utils/register.sv +src/ALU&ALUdecoder/ALUDecoder.v +src/ALU&ALUdecoder/ALU.v +src/Instruction_Decode/Instruction_Decode.v +src/Instruction_Decode/RegisterFile.v +src/ControlFSM.v +src/fetch.sv +src/top.v +src/extend.sv diff --git a/src/top.v b/src/top.v index a7d046e..3eb28e6 100644 --- a/src/top.v +++ b/src/top.v @@ -4,8 +4,10 @@ module top ( input wire clk , input wire reset ); - wire cfsm__pc_update; + wire cfsm__pc_update; + wire cfsm__pc_src; instr_t instr; + imm_t imm_ext; wire __tmp_AdrSrc , __tmp_IRWrite @@ -39,7 +41,14 @@ module top ( input wire clk ( .clk ( clk ) , .reset ( reset ) , .cfsm__pc_update ( cfsm__pc_update ) + , .cfsm__pc_src ( cfsm__pc_src ) + , .imm_ext ( imm_ext ) , .instr ( instr ) ); + extend extend + ( .in ( instr[31:20] ) + , .imm_ext ( imm_ext ) + ); + endmodule diff --git a/src/types.svh b/src/types.svh index 9958356..4fc0758 100644 --- a/src/types.svh +++ b/src/types.svh @@ -6,5 +6,6 @@ typedef logic [`PROCESSOR_BITNESS-1:0] instr_t; typedef logic [`PROCESSOR_BITNESS-1:0] addr_t; +typedef logic [`PROCESSOR_BITNESS-1:0] imm_t; `endif diff --git a/src/utils/mux.sv b/src/utils/mux.sv new file mode 100644 index 0000000..cdbbe26 --- /dev/null +++ b/src/utils/mux.sv @@ -0,0 +1,9 @@ +module mux #( parameter INPUT_WIDTH + , parameter INPUT_COUNT + ) + ( input wire [$clog2(INPUT_COUNT)-1:0] sel + , input wire [INPUT_WIDTH-1:0] in [INPUT_COUNT-1:0] + , output wire [INPUT_WIDTH-1:0] out + ); + assign out = in[sel]; +endmodule diff --git a/test/fetch_tb.sv b/test/fetch_tb.sv index 55b0207..bc0fd91 100644 --- a/test/fetch_tb.sv +++ b/test/fetch_tb.sv @@ -1,18 +1,23 @@ `timescale 1ns/1ps `include "src/utils.svh" +`include "src/types.svh" module fetch_tb; - reg clk; - reg reset; - reg cfsm__pc_update; - instr_t instr; + reg clk; + reg reset; + reg cfsm__pc_update; + reg cfsm__pc_src; + imm_t imm_ext; + instr_t instr; fetch uut ( .clk ( clk ) , .reset ( reset ) , .cfsm__pc_update ( cfsm__pc_update ) + , .cfsm__pc_src ( cfsm__pc_src ) + , .imm_ext ( imm_ext ) , .instr ( instr ) ); @@ -22,7 +27,10 @@ module fetch_tb; end initial begin + + // testing incrementing pc naturally cfsm__pc_update <= `FALSE; + cfsm__pc_src <= 1; 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); @@ -135,11 +143,70 @@ module fetch_tb; 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); + reset <= `TRUE; + #10; + reset <= `FALSE; + + // testing pc update via pc_target + uut.instruction_memory.M[64] = 32'hdeadbeef; + uut.instruction_memory.M[65] = 32'hfeedface; + uut.instruction_memory.M[66] = 32'hcafebabe; + uut.instruction_memory.M[128] = 32'hf00dcafe; + uut.instruction_memory.M[129] = 32'hd00dfafe; + + cfsm__pc_src <= 0; + imm_ext <= 32'h00000100; + + #10; + + assert(uut.pc_cur === 32'h00000100) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000200) 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'h00000200) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000300) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hf00dcafe) else $error("`instr` is `%0h`", instr); + + cfsm__pc_src <= 1; + + #10; + + assert(uut.pc_cur === 32'h00000204) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00000208) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hd00dfafe) else $error("`instr` is `%0h`", instr); + + imm_ext <= 32'h00002000; // out of memory bounds + cfsm__pc_src <= 0; + + #10; + + assert(uut.pc_cur === 32'h00002204) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00004204) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hxxxxxxxx) else $error("`instr` is `%0h`", instr); + + imm_ext <= 32'h0; // zero jump + + #10; + + assert(uut.pc_cur === 32'h00002204) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00002204) else $error("`uut.pc_next` is `%0h`", uut.pc_next); + assert(instr === 32'hxxxxxxxx) else $error("`instr` is `%0h`", instr); + + imm_ext <= -32'd1; // negative jump + + #10; + + assert(uut.pc_cur === 32'h00002203) else $error("`uut.pc_cur` is `%0h`", uut.pc_cur); + assert(uut.pc_next === 32'h00002202) 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"); + $dumpfile("test/fetch_tb.vcd"); $dumpvars(0, fetch_tb); end endmodule