diff --git a/rtl/verilog/defines.v b/rtl/verilog/defines.v new file mode 100644 index 0000000..633402d --- /dev/null +++ b/rtl/verilog/defines.v @@ -0,0 +1,9 @@ +`define ALU_ADD 0 +`define ALU_AND 1 +`define ALU_OR 2 +`define ALU_XOR 3 +`define ALU_SLT 4 +`define ALU_SUB 5 +`define ALU_DIV 6 +`define ALU_MUL 7 +`define ALU_NOR 8 diff --git a/rtl/verilog/qm_control.v b/rtl/verilog/qm_control.v new file mode 100644 index 0000000..a3ddc28 --- /dev/null +++ b/rtl/verilog/qm_control.v @@ -0,0 +1,131 @@ +`define OP_SPECIAL 6'b000000 +`define OP_SPECIAL2 6'b011100 + +`define OP_ADDI 6'b001000 // addi rt, rs, imm ; rt = rs + imm +`define OP_ADDIU 6'b001001 // addiu rt, rs, imm ; rt = rs + imm +`define OP_ANDI 6'b001100 // andi rt, rs, imm ; rt = rs & imm +`define OP_ORI 6'b001101 +`define OP_XORI 6'b001110 +`define OP_SLTI 6'b001010 +`define OP_SLTIU 6'b001011 + +`define OP_LB 6'b100000 +`define OP_LH 6'b100001 +`define OP_LBU 6'b100100 +`define OP_LHU 6'b100101 +`define OP_LW 6'b100011 // lw rt, imm(rs) ; rt = [rs+imm] +`define OP_SW 6'b101011 // sw rt, imm(rs) ; [rs + imm] = rt + +// Special 0 +`define FUNCT_ADD 6'b100000 +`define FUNCT_ADDU 6'b100001 +`define FUNCT_AND 6'b100100 +`define FUNCT_DIV 6'b011010 +`define FUNCT_DIVU 6'b011011 +`define FUNCT_MULT 6'b011000 +`define FUNCT_MULTU 6'b011001 +`define FUNCT_NOR 6'b100111 +`define FUNCT_OR 6'b100101 +`define FUNCT_SLT 6'b101010 +`define FUNCT_SUB 6'b100010 +`define FUNCT_SUBU 6'b100011 +`define FUNCT_XOR 6'b100110 + +// Special 2 +//`define FUNCT_CLO 6'b100001 +//`define FUNCT_CLZ 6'b100000 +//`define FUNCT_MADD 6'b000000 +//`define FUNCT_MADDU 6'b000001 +//`define FUNCT_MSUB 6'b000100 +//`define FUNCT_MSUBU 6'b000101 +//`define FUNCT_MUL 6'b000010 + +`include "defines.v" + +module qm_control( + /// Instruction from the decode stage + input wire [5:0] opcode, + input wire [5:0] funct, + + /// Control lines to the pipeline stages + // Mux selecting the destination register for the register writeback + // 0 - RT + // 1 - RD + output wire reg_destination, + // Mux selecting the source of the ALU B operand + // 0 - Value of RT register + // 1 - instruction Imediate part + output wire alu_source, + // ALU Control signal, select ALU operation + output wire [3:0] alu_control, + // Memory write enable signal + output wire mem_write, + // Mux selecting the source of the data for the register writeback + // 0 - output of ALU + // 1 - data read from memory + output wire reg_wsource, + // Register writeback enable signal + output wire reg_write + ); + +always @(opcode, funct) begin + case (opcode) + `OP_SPECIAL: begin + reg_destination <= 1; + alu_source <= 0; + mem_write <= 0; + reg_wsource <= 0; + reg_write <= 1; + case (funct) + `FUNCT_ADD: <= `ALU_ADD; + `FUNCT_ADDU: <= `ALU_ADD; + `FUNCT_AND: <= `ALU_AND; + `FUNCT_DIV: <= `ALU_DIV; + `FUNCT_DIVU: <= `ALU_DIV; + `FUNCT_MULT: <= `ALU_MUL; + `FUNCT_MULTU: <= `ALU_MUL; + `FUNCT_NOR: <= `ALU_NOR + `FUNCT_OR: <= `ALU_OR; + `FUNCT_SLT: <= `ALU_SLT; + `FUNCT_SUB: <= `ALU_SUB; + `FUNCT_SUBU: <= `ALU_SUB; + `FUNCT_XOR: <= `ALU_XOR; + endcase + end + `OP_LW: begin + reg_destination <= 0; + alu_source <= 1; + alu_control <= 0; + mem_write <= 0; + reg_wsource <= 1; + reg_write <= 1; + end + `OP_SW: begin + reg_destination <= 0; + alu_source <= 1; + alu_control <= 0; + mem_write <= 1; + reg_wsource <= 0; + reg_write <= 0; + end + 6'b001???: // all immediate arith/logic + default: begin + reg_destination <= 0; + alu_source <= 0; + mem_write <= 0; + reg_wsource <= 0; + reg_write <= 0; + case (opcode) + `OP_ADDI: alu_control <= `ALU_ADD; + `OP_ADDIU: alu_control <= `ALU_ADD; + `OP_ANDI: alu_control <= `ALU_AND; + `OP_ORI: alu_control <= `ALU_OR; + `OP_XORI: alu_control <= `ALU_XOR; + `OP_SLTI: alu_control <= `ALU_SLT; + `OP_SLTIU: alu_control <= `ALU_SLTIU; + endcase + end + endcase +end + +endmodule diff --git a/rtl/verilog/qm_fetch.v b/rtl/verilog/qm_fetch.v index e6f87a5..34c55b7 100644 --- a/rtl/verilog/qm_fetch.v +++ b/rtl/verilog/qm_fetch.v @@ -1,9 +1,29 @@ module qm_fetch( /// datapath + // input PC to assume + input wire [31:0] di_PC, // output instruction register output wire [31:0] do_IR, - // output next pc - output wire [31:0] do_NextPC -); + // output to next PC + output wire [31:0] do_NextPC, + + // icache connectivity + output wire [31:0] icache_address, + input wire icache_hit, + input wire icache_should_stall, + input wire [31:0] icache_data + ); + +assign icache_address = di_PC; + +always @(*) begin + if (icache_should_stall && !icache_hit) begin + do_NextPC = di_PC; + do_IR = 0; + end else begin + do_NextPC = di_PC + 4; + do_IR = icache_data; + end +end endmodule diff --git a/rtl/verilog/qm_icache.v b/rtl/verilog/qm_icache.v index e0cf974..2e6deec 100644 --- a/rtl/verilog/qm_icache.v +++ b/rtl/verilog/qm_icache.v @@ -76,7 +76,7 @@ always @(posedge clk) begin end // read condition -always @(address, lines) begin +always @(*) begin if (enable) begin // is this in the RAM region? if (32'h80000000 <= address && address < 32'h90000000) begin diff --git a/rtl/verilog/qm_regfile.v b/rtl/verilog/qm_regfile.v index 9d0a8fe..95bd6bd 100644 --- a/rtl/verilog/qm_regfile.v +++ b/rtl/verilog/qm_regfile.v @@ -15,12 +15,12 @@ module qm_regfile( reg [31:0] rf [31:0]; always @(wd3) begin - if (we3) begin + if (we3 && wa != 0) begin rf[wa3] = wd3; end end - assign rd1 = rf[ra1]; - assign rd2 = rf[ra2]; + assign rd1 = (ra1 == 0 ? 0 : rf[ra1]); + assign rd2 = (ra2 == 0 ? 0 : rf[ra2]); endmodule diff --git a/rtl/verilog/qm_top.v b/rtl/verilog/qm_top.v new file mode 100644 index 0000000..57626e6 --- /dev/null +++ b/rtl/verilog/qm_top.v @@ -0,0 +1,51 @@ +module qm_top( + +); + + +// Fetch / Decode +reg [31:0] FD_IR; +reg [31:0] FD_NextPC; + +// Decode / Execute +reg [31:0] DE_A; +reg [31:0] DE_B; +reg [31:0] DE_Imm; +reg [31:0] DE_IR; + +wire [31:0] ICache_Address; +wire [31:0] ICache_Data; +wire ICache_Hit; +wire ICache_ShouldStall; +// ICache +qm_icache icache( + .reset(reset), + .clk(sys_clk), + + .address(ICache_Address), + .data(ICache_Data), + .hit(ICache_Hit), + .stall(ICache_ShouldStall), + .enable(ICache_Enable) +); + +// Fetch +wire [31:0] fetch_IR; +wire [31:0] fetch_NextPC; +qm_fetch fetch( + .di_PC(FD_NextPC), + .do_IR(fetch_IR), + .do_NextPC(fetch_NextPC), + + .icache_address(ICache_Address), + .icache_hit(ICache_Hit), + .icache_should_stall(ICache_ShouldStall), + .icache_data(ICache_Data) +); +always @(posedge clk) begin + FD_IR <= fetch_IR; + FD_NextPC <= fetch_NextPC; +end + + +endmodule diff --git a/test/Makefile b/test/Makefile index 8e90f4f..6dc0dac 100644 --- a/test/Makefile +++ b/test/Makefile @@ -9,11 +9,14 @@ obj_dir/V%.cpp: ../rtl/verilog/%.v OBJS := /usr/share/verilator/include/verilated.cpp \ obj_dir/Vqm_decode.o \ obj_dir/Vqm_decode__Syms.cpp \ + obj_dir/Vqm_fetch.o \ + obj_dir/Vqm_fetch__Syms.cpp \ obj_dir/Vqm_icache.o \ obj_dir/Vqm_icache__Syms.cpp \ main.o \ test_decode.o \ - test_icache.o + test_icache.o \ + test_fetch.o test: $(OBJS) g++ $(CXXFLAGS) -o test $(OBJS) diff --git a/test/main.cpp b/test/main.cpp index 9fdbb20..beb7d39 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,10 +1,12 @@ #include "test_decode.h" #include "test_icache.h" +#include "test_fetch.h" int main(int argc, char **argv) { - test_decode(); - test_icache(); + //test_decode(); + //test_icache(); + test_fetch(); return 0; } diff --git a/test/test_fetch.cpp b/test/test_fetch.cpp new file mode 100644 index 0000000..68fab9b --- /dev/null +++ b/test/test_fetch.cpp @@ -0,0 +1,10 @@ +#include "test_fetch.h" + +#include + +#include "Vqm_fetch.h" + +void test_fetch(void) +{ + Vqm_fetch *fetch = new Vqm_fetch(); +} diff --git a/test/test_fetch.h b/test/test_fetch.h new file mode 100644 index 0000000..b1db027 --- /dev/null +++ b/test/test_fetch.h @@ -0,0 +1,6 @@ +#ifndef _TEST_FETCH_H +#define _TEST_FETCH_H + +void test_fetch(void); + +#endif