diff --git a/ALU.sv b/ALU.sv new file mode 100644 index 0000000..8f058e2 --- /dev/null +++ b/ALU.sv @@ -0,0 +1,38 @@ +`timescale 1ns / 1ps + +module ALU_HW_4(ALU_A, ALU_B, ALU_FUN, RESULT); + input signed [31:0] ALU_A; + input signed [31:0] ALU_B; //Two inputs from MUX outputs, output A and B + input logic [3:0] ALU_FUN; //4-bit input for option for ALU + output logic [31:0] RESULT; //32-bit output of ALU + + always_comb //Combinational logic (asynchronous clock) + begin + + case (ALU_FUN) //Case statement for different cases of ALU_fun + 1'b0 : RESULT = ALU_A + ALU_B; //ALU_FUN operation: add A and B + 4'b1000: RESULT = ALU_A - ALU_B; //ALU_FUN operation: subtract A from B + 4'b0110: RESULT = ALU_A | ALU_B; //ALU_FUN operation: OR A and B + 4'b0111: RESULT = ALU_A & ALU_B; //ALU_FUN operation: AND A and B + 4'b0100: RESULT = ALU_A ^ ALU_B; //ALU_FUN operation: XOR A and B + 4'b0101: RESULT = ALU_A >> ALU_B[4:0]; //ALU_FUN operation: Right-shift ALU_A the amount indicated by ALU_B, store in RESULT + 4'b0001: RESULT = ALU_A << ALU_B[4:0]; //ALU_FUN operation: Left-shift ALU_A the amount indicated by ALU_B, store in RESULT + 4'b1101: RESULT = ALU_A >>> ALU_B[4:0]; //ALU_FUN operation: Arithmetic right-shift ALU_A the amount indicated by ALU_B, store in RESULT + 4'b0010: if (ALU_A < ALU_B) RESULT = 1'b1; else RESULT = 1'b0; + //Statement above used when ALU_FUN is set to 1101 (set less than) + // When ALU_A < ALU_B, set RESULT equal to 1, else set it to 0 + 4'b0011: + begin //When ALU_FUN is set to 0011 (set less than unsigned), we need to recast the + // as unsigned values before we begin to compare them + //Once this is done, it's just a matter of following the same format as slt + if ($unsigned(ALU_A) < $unsigned(ALU_B)) RESULT = 1'b1; else RESULT = 1'b0; + end + 4'b1001: RESULT = ALU_A; + // For option 1001 (lui-copy), the ALU will grab the value provided + //by the 1st MUX (ALU_A). + default: RESULT = 0; + //Since we don't want default to do anything, we just let the default case do nothing (set to 0) + endcase + end + +endmodule \ No newline at end of file diff --git a/ALU_MUX_srcA.sv b/ALU_MUX_srcA.sv new file mode 100644 index 0000000..4be44c3 --- /dev/null +++ b/ALU_MUX_srcA.sv @@ -0,0 +1,13 @@ +module ALU_MUX_srcA(alu_srcA, REG_rs1, IMM_GEN_U_Type, srcA); + + input [31:0] REG_rs1, IMM_GEN_U_Type; + input alu_srcA; + output logic [31:0] srcA; + + always_comb begin + case (alu_srcA) + 1'b0: begin srcA = REG_rs1; end + 1'b1: begin srcA = IMM_GEN_U_Type; end + endcase + end +endmodule \ No newline at end of file diff --git a/ALU_MUX_srcB.sv b/ALU_MUX_srcB.sv new file mode 100644 index 0000000..3e2547e --- /dev/null +++ b/ALU_MUX_srcB.sv @@ -0,0 +1,17 @@ +`timescale 1ns / 1ps + +module ALU_MUX_srcB(REG_rs2, IMM_GEN_I_Type, IMM_GEN_S_Type, PC_OUT, alu_srcB, srcB); + + input [31:0] REG_rs2, IMM_GEN_I_Type, IMM_GEN_S_Type, PC_OUT; + input [1:0] alu_srcB; + output logic [31:0] srcB; + + always_comb begin + case (alu_srcB) + 1'b0: begin srcB = REG_rs2; end + 1'b1: begin srcB = IMM_GEN_I_Type; end + 2'b10: begin srcB = IMM_GEN_S_Type; end + 2'b11: begin srcB = PC_OUT; end + endcase + end +endmodule diff --git a/ALU_with_MUX.sv b/ALU_with_MUX.sv new file mode 100644 index 0000000..0139505 --- /dev/null +++ b/ALU_with_MUX.sv @@ -0,0 +1,33 @@ +`timescale 1ns / 1ps + +module ALU_with_MUX(REG_rs1, IMM_GEN_U_Type, alu_srcA, REG_rs2, IMM_GEN_I_Type, + IMM_GEN_S_Type, PC_OUT, alu_srcB, alu_fun, ALU_RESULT); + + // Inputs for MUX source A + input [31:0] REG_rs1, IMM_GEN_U_Type; + input alu_srcA; + // Logic for output of MUX_A to ALU + logic [31:0] srcA_to_ALU; + + //Inputs for MUX source B + input [31:0] REG_rs2, IMM_GEN_I_Type, IMM_GEN_S_Type, PC_OUT; + input [1:0] alu_srcB; + // Logic for output of MUX_B to ALU + logic [31:0] srcB_to_ALU; + + // Input for ALU_fun + input [3:0] alu_fun; + // Output for ALU + output logic [31:0] ALU_RESULT; + + ALU_MUX_srcA MUX_A (.REG_rs1(REG_rs1), .IMM_GEN_U_Type(IMM_GEN_U_Type), + .alu_srcA(alu_srcA), .srcA(srcA_to_ALU)); + + ALU_MUX_srcB MUX_B (.REG_rs2(REG_rs2), .IMM_GEN_I_Type(IMM_GEN_I_Type), + .IMM_GEN_S_Type(IMM_GEN_S_Type), .PC_OUT(PC_OUT), + .alu_srcB(alu_srcB), .srcB(srcB_to_ALU)); + + ALU_HW_4 ALU_with_MUXes (.ALU_A(srcA_to_ALU), .ALU_B(srcB_to_ALU), .ALU_FUN(alu_fun), + .RESULT(ALU_RESULT)); + +endmodule diff --git a/Branch_Addr_Gen_HW_5.sv b/Branch_Addr_Gen_HW_5.sv new file mode 100644 index 0000000..d97209a --- /dev/null +++ b/Branch_Addr_Gen_HW_5.sv @@ -0,0 +1,18 @@ +`timescale 1ns / 1ps + +module Branch_Addr_Gen_HW_5(PC_COUNT, J_INPUT, B_INPUT, + I_INPUT, RS1_INPUT, JALR_OUT, BRANCH_OUT, JAL_OUT); + + input [31:0] PC_COUNT, J_INPUT, B_INPUT, I_INPUT, RS1_INPUT; + output logic [31:0] JALR_OUT, BRANCH_OUT, JAL_OUT; + + always_comb begin + + BRANCH_OUT = PC_COUNT + B_INPUT; + + JAL_OUT = PC_COUNT + J_INPUT; + + JALR_OUT = RS1_INPUT + I_INPUT; + + end +endmodule diff --git a/Brand_Cond_Gen.sv b/Brand_Cond_Gen.sv new file mode 100644 index 0000000..0505397 --- /dev/null +++ b/Brand_Cond_Gen.sv @@ -0,0 +1,92 @@ +`timescale 1ns / 1ps + +module Brand_Cond_Gen (REG_INPUTA, REG_INPUTB, DR_MEM_OUT, PC_SOURCE_OUT); + + // Inputs of Branch Condition Generator: RS1, RS2, Memory Dout1 + input logic [31:0] REG_INPUTA, REG_INPUTB, DR_MEM_OUT; + // Output of Branch Condition Generator: PC_SOURCE_OUT + output logic [1:0] PC_SOURCE_OUT; + + // Asynchronous, use always_comb + +always_comb begin + + // Look at current option code for program being executed + case (DR_MEM_OUT[6:0]) + + + 7'b1100011: // First case: Branch instruction (Same OP Code, different funct3) or Jalr + begin + + case(DR_MEM_OUT[14:12]) // Check funct3 + + 3'b000: begin // Beq (Branch if equal) + // Check to see if current rs1 is equal to rs2. If so, set pcSource to 2. Otherwise, set to 0 + if (REG_INPUTA == REG_INPUTB) begin + PC_SOURCE_OUT = 2'b10; end + else begin PC_SOURCE_OUT = 1'b0; end + end + + 3'b101: begin // Bge (Branch if greater than or equal to) + // Check to see if inverse of blt is true. If so, set pcSource to 2. Otherwise, set to 0 + if (!($signed(REG_INPUTA) < $signed(REG_INPUTB))) begin + PC_SOURCE_OUT = 2'b10; end + else begin PC_SOURCE_OUT = 1'b0; end + end + + 3'b111: begin // Bgeu (Branch if greater than or equal to unsigned) + // Check to see if inverse of bltu is true. If so, set pcSource to 2. Otherwise, set to 0 + if (!(REG_INPUTA < REG_INPUTB)) begin + PC_SOURCE_OUT = 2'b10; end + else begin PC_SOURCE_OUT = 1'b0; end + end + + 3'b100: begin // Blt (Branch if less than) + // Check to see if less than is true. If so, set pcSource to 2. Otherwise, set to 0 + if ($signed(REG_INPUTA) < $signed(REG_INPUTB)) begin + PC_SOURCE_OUT = 2'b10; end + else begin PC_SOURCE_OUT = 1'b0; end + end + + 3'b110: begin // Bltu (Branch if less than unsigned) + // Check to see if less than unsigned is true. If so, set pcSource to 2. Otherwise, set to 0 + if (REG_INPUTA < REG_INPUTB) begin + PC_SOURCE_OUT = 2'b10; end + else begin PC_SOURCE_OUT = 1'b0; end + end + + 3'b001: begin // Bne (Branch if not equal) + // Check to see if inverse of equals is true. If so, set pcSource to 2. Otherwise, set to 0 + if(!(REG_INPUTA == REG_INPUTB)) begin + PC_SOURCE_OUT = 2'b10; end + else begin PC_SOURCE_OUT = 1'b0; end + end + + 3'b000: begin // jalr (Jump and link at register) + // Set pcSource to 1 + PC_SOURCE_OUT = 1'b1; + end + + default: begin // For all other cases: Default to 0 + PC_SOURCE_OUT =1'b0; + end + + endcase + + end + + 7'b1101111: begin // Second case: jal (Jump and link) + // Set pcSource to 3 + PC_SOURCE_OUT = 2'b11; + end + + default: begin// Default case: pcSource is set to 0 (PC + 4) + PC_SOURCE_OUT = 1'b0; + end + + endcase + +end + + +endmodule diff --git a/CSR.sv b/CSR.sv new file mode 100644 index 0000000..257040c --- /dev/null +++ b/CSR.sv @@ -0,0 +1,79 @@ +`timescale 1ns / 1ps + +module CSR_HW_8(RST, INT_TAKEN, ADDR, WR_EN, PC_ADDR, WD, CLK, CSR_MIE, CSR_MEPC, CSR_MTVEC, RD); + + input RST; + input INT_TAKEN; + input [11:0] ADDR; + input WR_EN; + input [31:0] PC_ADDR, WD; + input CLK; + output logic CSR_MIE; + output logic [31:0] CSR_MEPC, CSR_MTVEC, RD; + + + // Initialize CSR registers, 3 32-bit addresses + logic [31:0]CSR[0:2]; + + always_ff @ (posedge CLK) begin //Writing is synchronous, first check if reset is high + + if (RST) //On high Reset, set current CSRs to 0 + + begin + CSR[0] <= 1'b0; + CSR[1] <= 1'b0; + CSR[2] <= 1'b0; + end + + else + + if (WR_EN) begin//Now, check if csr_we is high. If so, check input addr to see where to write data + case(ADDR) + 12'h305: begin //Write input WD to mtvec register (CSR[1]) + CSR[1] <= WD; + end + + 12'h341: begin //Write current PC to mepc register (CSR[0]) + CSR[0] <= PC_ADDR; + end + + 12'h304: begin //Set mie to high (only consider bit 0) (CSR[2]) + CSR[2][0] <= WD[0]; + end + + default: + CSR[2] <= 1'b0; + endcase + end + + if (INT_TAKEN) begin //If an interrupt is taken, set mie back to 0 + CSR[0] <= PC_ADDR; + CSR[2][0] <= 1'b0; + end + + end + + always_comb begin //Reading is asynchronous + + CSR_MIE = CSR[2][0]; + CSR_MEPC = CSR[0]; + CSR_MTVEC = CSR[1]; + RD = 0; // :Initialized output + + case (ADDR) //Case for RD based on ADDR + + 12'h00000305: begin //RD mtvec register + RD = CSR[1]; end + + 12'h00000341: begin //RD mepc register + RD = CSR[0]; end + + 12'h00000304: begin //RD bit 0 of mie + RD = CSR[2][0]; end + + default: begin //Default to remove any latches + RD = 1'b0; end + + endcase + end +endmodule diff --git a/Decode_State.sv b/Decode_State.sv index 8e1d97c..f1a8654 100644 --- a/Decode_State.sv +++ b/Decode_State.sv @@ -58,7 +58,7 @@ module Decode_State(REG_CLOCK, REG_RESET, FR_MEM, FR_PC, FR_PC_4, DEC_PC_OUT, DE // ----------------------------------- Register File Setup ----------------------------------------------- - Register_File_HW_3 Reg_File (.CLOCK(REG_CLOCK), .WD(FR_MEM), .RF_RS1(REG_FILE_RS1), .RF_RS2(REG_FILE_RS2)); + Register_File_HW_3 Reg_File (.CLOCK(REG_CLOCK), .input_reg(FR_MEM), .RF_RS1(REG_FILE_RS1), .RF_RS2(REG_FILE_RS2)); // ----------------------------------- Immediate Generator Setup ----------------------------------------------- diff --git a/Execute_State.sv b/Execute_State.sv index 2c88361..bb929de 100644 --- a/Execute_State.sv +++ b/Execute_State.sv @@ -21,7 +21,8 @@ module Execute_State(EXECUTE_CLOCK, EXECUTE_RESET, DR_J_TYPE, DR_B_TYPE, DR_I_TYPE, DR_PC_MEM, DR_RS1, DR_RS2, DR_ALU_FUN, JALR_TO_PC, BRANCH_TO_PC, - JAL_TO_PC, PCSOURCE_TO_PC, DR_REG_WRITE, DR_MEM_WRITE, DR_MEM_READ2, DR_RF_WR_SEL, DR_PC_4); + JAL_TO_PC, PCSOURCE_TO_PC, DR_REG_WRITE, DR_MEM_WRITE, DR_MEM_READ2, DR_RF_WR_SEL, DR_PC_4, EXEC_PC_4, + EXEC_PC_MEM, EXEC_ALU_RESULT, EXEC_RS2, EXEC_RF_WR_SEL, EXEC_REGWRITE, EXEC_MEMWRITE, EXEC_MEMREAD2); // Inputs for clock and reset signals input EXECUTE_CLOCK, EXECUTE_RESET; @@ -68,9 +69,9 @@ module Execute_State(EXECUTE_CLOCK, EXECUTE_RESET, DR_J_TYPE, DR_B_TYPE, DR_I_TY // 2-bit: rf_wr_sel from Decode register // 1-bit from Decode register: regWrite, memWrite, memRead2 - logic [31:0] EXECUTE_REG1[0:3]; // 32-bit values - logic [1:0] EXECUTE_REG2; // 2-bit value - logic EXECUTE_REG3[0:2]; // 1-bit values + logic [31:0] EXECUTE_REG_1[0:3]; // 32-bit values + logic [1:0] EXECUTE_REG_2; // 2-bit value + logic EXECUTE_REG_3[0:2]; // 1-bit values // Save the various outputs on the negative edge of the clock cycle always_ff @ (negedge EXECUTE_CLOCK) begin @@ -82,12 +83,12 @@ module Execute_State(EXECUTE_CLOCK, EXECUTE_RESET, DR_J_TYPE, DR_B_TYPE, DR_I_TY EXECUTE_REG_1[3] <= DR_RS2; // rs2 from Decode register // 2- bit value - EXECUTE_REG2 <= DR_RF_WR_SEL; // RF_WR_SEL from Decode register + EXECUTE_REG_2 <= DR_RF_WR_SEL; // RF_WR_SEL from Decode register // 1-bit values - EXECUTE_REG3[0] <= DR_REG_WRITE; // regWrite from Decode register - EXECUTE_REG3[1] <= DR_MEM_WRITE; // memWrite from Decode register - EXECUTE_REG3[2] <= DR_MEM_READ2; // memRead2 from Decode register + EXECUTE_REG_3[0] <= DR_REG_WRITE; // regWrite from Decode register + EXECUTE_REG_3[1] <= DR_MEM_WRITE; // memWrite from Decode register + EXECUTE_REG_3[2] <= DR_MEM_READ2; // memRead2 from Decode register end diff --git a/Imm_Gen.sv b/Imm_Gen.sv new file mode 100644 index 0000000..c13a1ce --- /dev/null +++ b/Imm_Gen.sv @@ -0,0 +1,31 @@ +`timescale 1ns / 1ps + + +module Imm_Gen(IR_INPUT, U_TYPE_OUT, I_TYPE_OUT, S_TYPE_OUT, + J_TYPE_OUT, B_TYPE_OUT); + + input [31:0] IR_INPUT; //Input of IR that will undergo concatenation + output [31:0] U_TYPE_OUT, I_TYPE_OUT, S_TYPE_OUT, + J_TYPE_OUT, B_TYPE_OUT; //32-bit outputs of each type + + //Now, concatenate and replicate values for output + + + assign U_TYPE_OUT = {{IR_INPUT [31:12]}, {12'b0}}; + //Concatenated output of U_TYPE_OUT + assign I_TYPE_OUT = { {21{IR_INPUT[31]}}, IR_INPUT[30:20]}; + //Concatenated output of I_TYPE_OUT + assign S_TYPE_OUT = {{21{IR_INPUT[31]}}, IR_INPUT[30:25], + IR_INPUT[11:7]}; + //Concatenated output of S_TYPE_OUT + assign B_TYPE_OUT = {{20{IR_INPUT[31]}}, IR_INPUT[7], IR_INPUT[30:25], + IR_INPUT[11:8], 1'b0}; + //Concatenated output of B_TYPE_OUT + assign J_TYPE_OUT = {{12{IR_INPUT[31]}}, IR_INPUT[19:12], + IR_INPUT[20], IR_INPUT[30:21], 1'b0}; + //Concatenated output of J_TYPE_OUT + + //Concatenations above were done based on the Hardware 4 + // lab manual + +endmodule diff --git a/Memory_State.sv b/Memory_State.sv index 81508a1..bb7f69c 100644 --- a/Memory_State.sv +++ b/Memory_State.sv @@ -20,17 +20,19 @@ ////////////////////////////////////////////////////////////////////////////////// -module Memory_State(); +module Memory_State(MEM_CLOCK, MEM_RESET, ER_memWrite, ER_memRead2, ER_REG_WRITE, ER_PC_MEM, ER_PC_4, ER_ALU_OUT, + ER_RS2, ER_RF_WR_SEL, M_IOBUS_ADDR, M_IOBUS_OUT, M_IOBUS_WR, MEM_REG_DOUT2, MEM_REG_ALU_RESULT, MEM_REG_IR, + MEM_REG_PC_4, MEM_RF_WR_SEL, MEM_REG_WRITE); // Inputs for Memory register input MEM_CLOCK, MEM_RESET; // Inputs from Execute register - input logic ER_memWrite, ER_memRead2, ER_MEM_REG_WRITE; + input logic ER_memWrite, ER_memRead2, ER_REG_WRITE; input logic [31:0] ER_PC_MEM, ER_PC_4, ER_ALU_OUT, ER_RS2; input logic [1:0] ER_RF_WR_SEL; // Output for IOBUS_ADDR, IOBUS_OUT, IOBUS_WR - output logic [31:0] IOBUS_ADDR, IOBUS_OUT, IOBUS_WR; + output logic [31:0] M_IOBUS_ADDR, M_IOBUS_OUT, M_IOBUS_WR; // Wire for Memory dout2 logic [31:0] DOUT2_TO_MEM_REG; @@ -44,12 +46,12 @@ module Memory_State(); // Memory Module setup Memory Mem_Module (.MEM_ADDR2(ER_ALU_OUT), .MEM_DIN2(ER_RS2), .MEM_WE2(ER_memWrite), .MEM_RDEN2(ER_memRead2), - .MEM_SIZE(ER_PC_MEM[14:12]), .IO_WR(IOBUS_WR), .MEM_DOUT2(DOUT2_TO_MEM_REG)); + .MEM_SIZE(ER_PC_MEM[14:12]), .IO_WR(M_IOBUS_WR), .MEM_DOUT2(DOUT2_TO_MEM_REG)); // Still need to assign IOBUS_IN // Taking care of IOBUS..... - assign IOBUS_ADDR = ER_ALU_OUT; - assign IOBUS_OUT = ER_RS2; + assign M_IOBUS_ADDR = ER_ALU_OUT; + assign M_IOBUS_OUT = ER_RS2; // ----------------------------------- Memory Register Setup ----------------------------------------------- // Initalize Execute Register to hold the following values: @@ -75,11 +77,11 @@ module Memory_State(); MEMORY_REG_2 <= ER_RF_WR_SEL; // 1-bit value - MEMORY_REG_3 <= ER_PC_MEM; + MEMORY_REG_3 <= ER_REG_WRITE; end // Reading from the Fetch register should happen on the positive edge of the clock - always_ff @ (posedge EXECUTE_CLOCK) begin + always_ff @ (posedge MEM_CLOCK) begin // 32-bit reads MEM_REG_PC_4 <= MEMORY_REG_1[0]; diff --git a/OTTER_Multicycle.zip b/OTTER_Multicycle.zip deleted file mode 100644 index 68c9682..0000000 Binary files a/OTTER_Multicycle.zip and /dev/null differ diff --git a/OTTER_Multicycle_tb.sv b/OTTER_Multicycle_tb.sv new file mode 100644 index 0000000..8d9073c --- /dev/null +++ b/OTTER_Multicycle_tb.sv @@ -0,0 +1,21 @@ +`timescale 1ns / 1ps + + +module OTTER_Multicycle_tb(); + + logic cpu_clk, reset, iobus_wr; + logic [31:0] iobus_in, iobus_out, iobus_addr; + + always #5 cpu_clk = ~cpu_clk; + + Pipelined_MCU UUT (.CLK(cpu_clk), .RST(reset), .IOBUS_IN(iobus_in), // Inputs + .IOBUS_WR(iobus_wr), .IOBUS_OUT(iobus_out), .IOBUS_ADDR(iobus_addr)); // Outputs + + initial begin + iobus_in = 32'h00000002; + cpu_clk = 0; + reset = 1; + #10 reset = 0; + end + +endmodule diff --git a/PC_4.sv b/PC_4.sv new file mode 100644 index 0000000..97d4552 --- /dev/null +++ b/PC_4.sv @@ -0,0 +1,10 @@ +`timescale 1ns / 1ps + +module PC_4(Program_count, PC_4); + input [31:0] Program_count; + output logic [31:0] PC_4; + +always_comb begin + PC_4 = Program_count + 3'b100; +end +endmodule diff --git a/PC_With_MUX.sv b/PC_With_MUX.sv new file mode 100644 index 0000000..72c5235 --- /dev/null +++ b/PC_With_MUX.sv @@ -0,0 +1,23 @@ +`timescale 1ns / 1ps + +module PC_With_MUX(MUX_IN_JALR, MUX_IN_BRANCH, + MUX_IN_JAL, MUX_IN_MTVEC, MUX_IN_MEPC, PC_WRITE, PC_RST, CLK, PC_SOURCE, + PC_ADDRESS, PC_4_to_MUX); + +input [31:0] MUX_IN_JALR, MUX_IN_BRANCH, MUX_IN_JAL, MUX_IN_MTVEC, MUX_IN_MEPC; //Serves as the 6 32-bit signals for the input to the MUX +input PC_WRITE, PC_RST, CLK; //Serve as the inputs for the PC +input [2:0]PC_SOURCE; //Serves as the input for the selector of the MUX +output logic [31:0]PC_ADDRESS; //Serves as the output for the PC +logic [31:0]Mux_to_PC; //Logic to connect MUX to PC +output logic [31:0] PC_4_to_MUX; //Logic to connect PC to PC_4 + +PC_MUX MyMUX (.MUX_SEL(PC_SOURCE), .PC_4(PC_4_to_MUX), .JALR(MUX_IN_JALR), +.BRANCH(MUX_IN_BRANCH), .JAL(MUX_IN_JAL), .MTVEC(MUX_IN_MTVEC), .MEPC(MUX_IN_MEPC), //Creation of MUX with inputs/outputs +.MUX_OUT(Mux_to_PC)); + +Program_Counter MyCounter (.pc_write(PC_WRITE), .pc_rst(PC_RST), //Creation of PC with inputs/outputs +.pc_clk(CLK), .PC_DIN(Mux_to_PC), .PC_CNT(PC_ADDRESS)); + +PC_4 PC_Increment (.Program_count(PC_ADDRESS), .PC_4(PC_4_to_MUX)); +endmodule + diff --git a/Pipelined_MCU.sv b/Pipelined_MCU.sv index 221fc4e..115adc5 100644 --- a/Pipelined_MCU.sv +++ b/Pipelined_MCU.sv @@ -20,7 +20,80 @@ ////////////////////////////////////////////////////////////////////////////////// -module Pipelined_MCU( +module Pipelined_MCU(RST, CLK, IOBUS_IN, IOBUS_WR, IOBUS_OUT, IOBUS_ADDR); + + // Main inputs/outputs of OTTER MCU + input logic RST, CLK; + input logic [31:0] IOBUS_IN; + output IOBUS_WR; + output [31:0] IOBUS_OUT, IOBUS_ADDR; + + // Logics to connect outputs of Fetch State module to Decode State module + logic [31:0] Fetch_reg_PC_4, Fetch_reg_dout1, Fetch_reg_pc; + + // Logics to connect PC MUX inputs from Execute state + logic [31:0] Execute_jalr_to_MUX, Execute_branch_to_MUX, Execute_jal_to_MUX; + + // Temporary logic for PC_WRITE + logic pc_write; + assign pc_write = 1'b1; + // --------------------------------- Fetch State Setup----------------------------------------------- + + Fetch_State FS (.CLOCK(CLK), .RESET(RST), .FETCH_REG_OUT(Fetch_reg_dout1), .FETCH_REG_PC(Fetch_reg_pc), + .FETCH_REG_PC_4(Fetch_reg_PC_4), .MUX_JALR(Execute_jalr_to_MUX), .MUX_BRANCH(Execute_branch_to_MUX), + .MUX_JAL(Execute_jal_to_MUX), .PC_WRITE(pc_write), .PC_SOURCE(pcsource_to_pc)); + + // --------------------------------- Decode State Setup----------------------------------------------- - ); + // Logics to connect outputs of Decode state to Execute State + logic [31:0] Decoder_PC_4, Decoder_rs1, Decoder_rs2, Decoder_J_type, Decoder_B_type, Decoder_I_type, Decoder_dout1; + logic [3:0] Decoder_alu_fun; + logic Decoder_regWrite, Decoder_memWrite, Decoder_memRead2; + logic [1:0] Decoder_rf_wr_sel; + + Decode_State DS (.REG_CLOCK(CLK), .REG_RESET(RST), .FR_MEM(Fetch_reg_dout1), .FR_PC(Fetch_reg_pc), .FR_PC_4(Fetch_reg_PC_4), // Inputs + .DEC_PC_OUT(Decoder_PC_4), .DEC_ALU_A(Decoder_rs1), .DEC_ALU_B(Decoder_rs2), .DEC_J_TYPE(Decoder_J_type), // Outputs + .DEC_B_TYPE(Decoder_B_type), .DEC_I_TYPE(Decoder_I_type), .DEC_MEM_IR(Decoder_dout1), .DEC_ALU_FUN(Decoder_alu_fun), + .DEC_REGWRITE(Decoder_regWrite), .DEC_MEMWRITE(Decoder_memWrite), .DEC_MEMREAD_2(Decoder_memRead2), + .DEC_RF_WR_SEL(Decoder_rf_wr_sel)); + + // --------------------------------- Execute State Setup----------------------------------------------- + + // Logics to connect outputs of Execute state to Memory State + logic [31:0] Execute_PC_4, Execute_dout1, Execute_alu_out, Execute_rs2; + logic [1:0] Execute_rf_wr_sel; + logic Execute_regWrite, Execute_memWrite, Execute_memRead2; + logic [1:0] pcsource_to_pc; + + Execute_State ES (.EXECUTE_CLOCK(CLK), .EXECUTE_RESET(RST), .DR_J_TYPE(Decoder_J_type), .DR_B_TYPE(Decoder_B_type), // Inputs + .DR_I_TYPE(Decoder_I_type), .DR_PC_MEM(Decoder_dout1), .DR_RS1(Decoder_rs1), .DR_RS2(Decoder_rs2), + .DR_ALU_FUN(Decoder_alu_fun), .DR_REG_WRITE(Decoder_regWrite), .DR_MEM_WRITE(Decoder_memWrite), + .DR_MEM_READ2(Decoder_memRead2), .DR_RF_WR_SEL(Decoder_rf_wr_sel), .DR_PC_4(Decoder_PC_4), + .EXEC_PC_4(Execute_PC_4), .EXEC_PC_MEM(Execute_dout1), .EXEC_ALU_RESULT(Execute_alu_out), // Outputs + .EXEC_RS2(Execute_rs2), .EXEC_RF_WR_SEL(Execute_rf_wr_sel), .EXEC_REGWRITE(Execute_regWrite), + .EXEC_MEMWRITE(Execute_memWrite), .EXEC_MEMREAD2(Execute_memRead2), + .JALR_TO_PC(Execute_jalr_to_MUX ), .JAL_TO_PC(Execute_jal_to_MUX), + .BRANCH_TO_PC(Execute_branch_to_MUX), .PCSOURCE_TO_PC(pcsource_to_pc)); // Outputs to PC in Fetch State + + // --------------------------------- Memory State Setup----------------------------------------------- + + // Logics to connect outputs of Memory state to Writeback State + logic [31:0] Memory_dout2, Memory_alu_out, Memory_dout1, Memory_PC_4; + logic [1:0] Memory_rf_wr_sel; + logic Memory_regWrite; + + Memory_State MS (.MEM_CLOCK(CLK), .MEM_RESET(RST), .ER_memWrite(Execute_memWrite), .ER_memRead2(Execute_memRead2), // Inputs + .ER_REG_WRITE(Execute_regWrite), .ER_PC_MEM(Execute_dout1), .ER_PC_4(Execute_PC_4), .ER_ALU_OUT(Execute_alu_out), + .ER_RS2(Execute_rs2), .ER_RF_WR_SEL(Execute_rf_wr_sel), + .M_IOBUS_ADDR(IOBUS_ADDR), .M_IOBUS_OUT(IOBUS_OUT), .M_IOBUS_WR(IOBUS_WR), .MEM_REG_DOUT2(Memory_dout2), // Outputs + .MEM_REG_ALU_RESULT(Memory_alu_out), .MEM_REG_IR(Memory_dout1), .MEM_REG_PC_4(Memory_PC_4), + .MEM_RF_WR_SEL(Memory_rf_wr_sel), .MEM_REG_WRITE(Memory_regWrite)); + + // --------------------------------- Writeback State Setup----------------------------------------------- + + Writeback_State WS (.MR_dout2(Memory_dout2), .MR_alu_result(Memory_alu_out), .MR_ir(Memory_dout1), .MR_PC_4(Memory_PC_4), // Inputs + .MR_rf_wr_sel(Memory_rf_wr_sel), .MR_regWrite(Memory_regWrite)); + + + endmodule diff --git a/Program_Counter.sv b/Program_Counter.sv new file mode 100644 index 0000000..81b310c --- /dev/null +++ b/Program_Counter.sv @@ -0,0 +1,19 @@ +`timescale 1ns / 1ps + +module Program_Counter( +input pc_write, pc_rst, pc_clk, +input [31:0]PC_DIN, output logic [31:0]PC_CNT); + +always_ff @ (posedge pc_clk) + begin + if (pc_rst == 1'b1) //First check, when reset = 1, output should be 0 + PC_CNT <= 32'h00; + else + if (pc_write == 1'b1) //Only write when pc_write is high + PC_CNT <= PC_DIN; //Output value to PC_CNT + if (PC_CNT >= 32'hFFFFFFFF) //Since PC_CNT is only able to accept values up to 32-bits + //We need to reset PC_CNT back to 0 once it reaches a number greater than this + PC_CNT <= 32'h00; + end + +endmodule diff --git a/Reg_File_with_MUX.sv b/Reg_File_with_MUX.sv new file mode 100644 index 0000000..2637011 --- /dev/null +++ b/Reg_File_with_MUX.sv @@ -0,0 +1,27 @@ +`timescale 1ns / 1ps + +module Reg_File_with_MUX(ALU_OUT, MEM_DOUT_2, CSR_RD, PC_4_OUT, RF_WR_SEL, + CLOCK, regWrite, input_reg, RF_RS1, RF_RS2); + + //Inputs/outputs of MUX outside REG_FILE + input [31:0] ALU_OUT, MEM_DOUT_2, CSR_RD, PC_4_OUT; + input [1:0] RF_WR_SEL; + + //Inputs/outputs of Reg_File + input CLOCK; // Input clock for reg_file + input regWrite; //Input en, can be 0 or 1 to write wd to wa + input [31:0] input_reg; //Input register + output logic [31:0] RF_RS1; + output logic [31:0] RF_RS2; //32-bit outputs RS1 and RS2 + + // Logic for output of MUX outside Reg_file + logic [31:0] Mux_to_RegFile; + + Reg_file_MUX Mux (.ALU_OUT(ALU_OUT), .MEM_DOUT_2(MEM_DOUT_2), .CSR_RD(CSR_RD), + .PC_OUT(PC_4_OUT), .RF_WR_SEL(RF_WR_SEL), .MUX_OUT(Mux_to_RegFile)); + + Register_File_HW_3 RegFile (.CLOCK(CLOCK), .WD(Mux_to_RegFile), .ENABLE(regWrite), + .input_reg(input_reg), .RF_RS1(RF_RS1), .RF_RS2(RF_RS2)); + + +endmodule diff --git a/Reg_file_MUX.sv b/Reg_file_MUX.sv new file mode 100644 index 0000000..ad4ff56 --- /dev/null +++ b/Reg_file_MUX.sv @@ -0,0 +1,17 @@ +`timescale 1ns / 1ps + +module Reg_file_MUX(ALU_OUT, MEM_DOUT_2, CSR_RD, PC_OUT, RF_WR_SEL, MUX_OUT); + + input [31:0] ALU_OUT, MEM_DOUT_2, CSR_RD, PC_OUT; + input [1:0] RF_WR_SEL; + output logic [31:0] MUX_OUT; + + always_comb begin + case (RF_WR_SEL) + 2'b00: begin MUX_OUT = PC_OUT; end// Select PC_OUT + 2'b01: begin MUX_OUT = CSR_RD ; end// Select CSR_RD + 2'b10: begin MUX_OUT = MEM_DOUT_2 ; end// Select MEM_DOUT_2 + 2'b11: begin MUX_OUT = ALU_OUT ; end// Select ALU_OUT + endcase + end +endmodule diff --git a/Register_File_HW_3.sv b/Register_File_HW_3.sv new file mode 100644 index 0000000..8846f53 --- /dev/null +++ b/Register_File_HW_3.sv @@ -0,0 +1,43 @@ +`timescale 1ns / 1ps + +module Register_File_HW_3(CLOCK, WD, ENABLE, input_reg, RF_RS1, RF_RS2); + + input CLOCK; // Input clock for reg_file + input [31:0] WD; //Input wd + input ENABLE; //Input en, can be 0 or 1 to write wd to wa + input [31:0] input_reg; //Input register + output logic [31:0] RF_RS1; + output logic [31:0] RF_RS2; //32-bit outputs RS1 and RS2 + + logic [31:0]RAM[0:31]; //Input RAM + logic [4:0] adr1, adr2, wa; // Logics for adr1, adr2, and wa + + //Intitalize RAM + initial begin + int i; + for (i=0; i<32; i=i+1) begin + RAM[i] = 0; + end +end + + always_comb begin + adr1 = input_reg[19:15]; //assign address 1 value to the specified bits from input_reg + adr2 = input_reg[24:20]; //assign address 2 value to the specified bits from input_reg + wa = input_reg[11:7]; ////assign wa to the specified bits from input_reg + //Note: Specified bits from input_reg determined by OTTR_architecture + + //Asynchronous from CLOCK, output values at specified RAM address + RF_RS1 = RAM[adr1]; + RF_RS2 = RAM[adr2]; + end + +//Whenever clock is HIGH +always_ff @ (posedge CLOCK) + begin + if(ENABLE) //When enable is HIGH, set data specified RAM address determined by wa equal to wd (saving data) + begin + RAM[wa] <= WD; + end //Set value at register 0 equal to 0 (hardwired to 0) + RAM[0] <= 32'h00; + end +endmodule diff --git a/Writeback_State.sv b/Writeback_State.sv index 166b068..96e58e2 100644 --- a/Writeback_State.sv +++ b/Writeback_State.sv @@ -41,6 +41,6 @@ module Writeback_State(MR_dout2, MR_alu_result, MR_ir, MR_PC_4, MR_rf_wr_sel, MR // ----------------------------------- Register File Setup ----------------------------------------------- - Register_File_HW_3 Reg_File (.WD(MUX_OUT_TO_REG_FILE), .wa(MR_ir[11:7]), .ENABLE(MR_regWrite)); + Register_File_HW_3 Reg_File (.WD(MUX_OUT_TO_REG_FILE), .ENABLE(MR_regWrite)); endmodule diff --git a/cu_decoder.sv b/cu_decoder.sv new file mode 100644 index 0000000..a1e2484 --- /dev/null +++ b/cu_decoder.sv @@ -0,0 +1,305 @@ +`timescale 1ns / 1ps + +module cu_decoder(IR_FETCH_REG, ALU_FUN, ALU_SOURCE_A, ALU_SOURCE_B, +RF_WR_SEL, REG_WRITE, MEM_WRITE, MEM_READ_2); + + // Input from Fetch Register + input logic [31:0] IR_FETCH_REG; + // Various outputs of Decoder + output logic [3:0] ALU_FUN; + output logic ALU_SOURCE_A; + output logic [1:0] ALU_SOURCE_B, RF_WR_SEL; + // New outputs: regWrite, memWrite, memRead2 + output logic REG_WRITE, MEM_WRITE, MEM_READ_2; + + + // Since both R-type and I-type instructions have the same output signals for the following: + // PC_SOURCE, RF_WR_SEL, ALU_SOURCE_A, ALU_SOURCE_B, ALU_FUN + // We can check to see what FUNCT3 is instead + + // Combinational logic, asynchronous +always_comb + +begin +// Initialize all outputs to 0 +ALU_FUN = 1'b0; +ALU_SOURCE_A = 1'b0; +ALU_SOURCE_B = 1'b0; +RF_WR_SEL = 1'b0; +REG_WRITE = 1'b0; +MEM_WRITE = 1'b0; +MEM_READ_2 = 1'b0; + + // Look at last 7 bits of IR + case (IR_FETCH_REG[6:0]) + + 7'b0110011: //R-type opcode + begin + //Set ALU_SOURCE_A to 0 + ALU_SOURCE_A = 1'b0; + //Set ALU_SOURCE_B to 0 + ALU_SOURCE_B = 1'b0; + // Set RF_WR_SEL to 3 + RF_WR_SEL = 2'b11; + // Set REG_WRITE to 1 + REG_WRITE = 1'b1; + // Set MEM_WRITE to 1 + MEM_WRITE = 1'b0; + // MEM_READ_2 = 1'b0 + MEM_READ_2 = 1'b0; + + //------------------------ STOPPED HERE ---------------------- + + // Check OP_CODE for ALU_FUN + case (IR_FETCH_REG[14:12]) + + 3'b010: //Set less than + begin ALU_FUN = 4'b0010; end + + 3'b100: //XOR + begin ALU_FUN = 4'b0100; end + + 3'b111: //AND + begin ALU_FUN = 4'b0111; end + + 3'b110: //OR + begin ALU_FUN = 4'b0110; end + + 3'b001: //Sll + begin ALU_FUN = 4'b0001; end + + 3'b011: //Sltu + begin ALU_FUN = 4'b0011; end + + // Cases that consider the 30th bit: Add/Sub and Sra/Srl + + 3'b000: //Add or Sub + case (IR_FETCH_REG[30]) + 1'b0: //Add + begin ALU_FUN = 4'b0000; end + 1'b1: //Sub + begin ALU_FUN = 4'b1000; end + default: + begin ALU_FUN = 4'b0000; end + endcase + 3'b101: //Sra or Srl + case (IR_FETCH_REG[30]) + 1'b0: //Srl + begin ALU_FUN = 4'b0101; end + 1'b1: //Sra + begin ALU_FUN =4'b1101; end + default: + begin ALU_FUN =4'b0101; end + endcase + + default: //Funct3 default case + ALU_FUN = 1'b0; + + endcase //Funct3 endcase + end //Funct3 end + + 7'b0010011: //I-Type opcode (no load operations / jalr) + begin + //Set ALU_SOURCE_A to 0 + ALU_SOURCE_A = 1'b0; + //Set ALU_SOURCE_B to 1 + ALU_SOURCE_B = 1'b1; + // Set RF_WR_SEL to 3 + RF_WR_SEL = 2'b11; + // Set REG_WRITE to 1 + REG_WRITE = 1'b1; + // Check OP_CODE for ALU_FUN + case (IR_FETCH_REG[14:12]) + + 3'b000: //Addi + begin ALU_FUN = 4'b0000; end + + 3'b111: //Andi + begin ALU_FUN = 4'b0111; end + + 3'b001: //Slli + begin ALU_FUN = 4'b0001; end + + 3'b110: //Ori + begin ALU_FUN = 4'b0110; end + + 3'b010: //slti + begin ALU_FUN = 4'b0010; end + + 3'b011: //sltiu + begin ALU_FUN = 4'b0011; end + + 3'b100: //Xori + begin ALU_FUN = 4'b0100; end + + // Case that considers the 30th bit: Srai or Srli + + 3'b101: //Srai or Srli + begin + case(IR_FETCH_REG[30]) + 1'b0: //Srli + begin ALU_FUN = 4'b0101; end + 1'b1: //Srai + begin ALU_FUN = 4'b1101; end + endcase + end + + default: + ALU_FUN = 1'b0; + + endcase + end + + 7'b0000011: // I-type load operations, not concerned with opcode (opcode determines size, sign) + begin // Now need to add high signal for memRead2 + //Set ALU_SOURCE_A to 0 + ALU_SOURCE_A = 1'b0; + //Set ALU_SOURCE_B to 1 + ALU_SOURCE_B = 1'b1; + //Set ALU_FUN to 0 + ALU_FUN = 4'b0000; + //Set rf_wr_sel to 2 + RF_WR_SEL = 2'b10; + // Set MEM_READ_2 to 1 + MEM_READ_2 = 1'b1; + // Set regWrite to high + REG_WRITE = 1'b1; + end + + 7'b0100011: //S-type operations + begin // Now need to add high signal for memWrite + //Set ALU_FUN to 0 + ALU_FUN = 4'b0000; + //Set ALU_SOURCE_A to 0 + ALU_SOURCE_A = 1'b0; + //Set ALU_SOURCE_B to 2 + ALU_SOURCE_B = 2'b10; + //Set rf_we_sel to 2 + RF_WR_SEL = 2'b10; + // Set memWrite to 1 + MEM_WRITE = 1'b1; + end + + 7'b0110111: //Lui, U-type + begin + //Set ALU_SOURCE_A to 1 + ALU_SOURCE_A = 1'b1; + // Ignore value of ALU_SOURCE_B + // Set RF_WR_SEL to 3 + RF_WR_SEL = 2'b11; + // Set ALU_FUN to 1001 + ALU_FUN = 4'b1001; + end + + 7'b0010111: //Auipc, U-type + begin + //Set ALU_SOURCE_A to 1 + ALU_SOURCE_A = 1'b1; + // Set ALU_SOURCE_B to 3 + ALU_SOURCE_B = 2'b11; + // Set RF_WR_SEL to 3 + RF_WR_SEL = 2'b11; + // Set ALU_FUN to 0000 + ALU_FUN = 4'b0000; + end + +// ---------------------------------- B-type code now taken care of by Branch Condition Generator ------------------- + +// 7'b1100011: // B-type opcode +// begin +// case (IR_FETCH_REG[14:12]) +// 3'b000: //Branch if equal opcode +// begin +// // First, check to see if br_eq is 1. If so, set PC_SOURCE to 2, otherwise set PC_SOURCE to 0 +// case (BR_EQ) +// 1'b1: +// begin PC_SOURCE = 3'b010; end +// default: +// PC_SOURCE = 1'b0; +// endcase +// end + +// 3'b101: //Branch if greater than or equal +// begin +// case(BR_LT) //Check to see if BR_LT is 0. If so, set PC_Source to 2. Otherwise, PC_Source = 0 +// 1'b0: +// begin PC_SOURCE =3'b010; end +// default: +// PC_SOURCE = 1'b0; +// endcase +// end + +// 3'b111: //Branch if greater than or equal unsigned +// begin +// case(BR_LTU) //Check to see if BR_LTU is 0. If so, set PC_Source to 2. Otherwise, PC_Source = 0 +// 1'b0: +// begin PC_SOURCE =3'b010; end +// default: +// PC_SOURCE = 1'b0; +// endcase +// end + +// 3'b100: //Branch if less than +// begin +// case(BR_LT) //Check to see if BR_LT is 1. If so, set PC_Source to 2. Otherwise, PC_Source = 0 +// 1'b1: +// begin PC_SOURCE =3'b010; end +// default: +// PC_SOURCE = 1'b0; +// endcase +// end + +// 3'b110: //Branch if less than unsigned +// begin +// case(BR_LTU) //Check to see if BR_LTU is 1. If so, set PC_Source to 2. Otherwise, PC_Source = 0 +// 1'b1: +// begin PC_SOURCE =3'b010; end +// default: +// PC_SOURCE = 1'b0; +// endcase +// end + +// 3'b001: //Branch if not equal opcode +// begin +// case (BR_EQ) // First, check to see if br_eq is 0. If so, set PC_SOURCE to 2, otherwise set PC_SOURCE to 0 +// 1'b0: +// begin PC_SOURCE = 3'b010; end +// default: +// PC_SOURCE = 1'b0; +// endcase +// end + +// default: +// ALU_FUN = 1'b0; +// endcase +// end + + 7'b1101111: //J-type jal instruction + begin + //Set rf_wr_sel to 0 + RF_WR_SEL = 1'b0; + end + + 7'b1100111: //I-type jalr instruction + begin + //Set rf_wr_sel to 0 + RF_WR_SEL = 1'b0; + end + +// ---------------------------------- csrrw and mret commented out for now ------------------- + +// 7'b1110011: //csrrw or mret instruction +// case(FUNCT3) +// 3'b001: //csrrw instruction +// begin PC_SOURCE = 1'b0; +// RF_WR_SEL = 3'b010; end + +// 3'b000: +// begin PC_SOURCE = 3'b101; end +// endcase + +// default: //Default for OP_CODE +// ALU_FUN = 1'b0; + endcase +end +endmodule diff --git a/otter_mcu_pipeline_template_v2.sv b/otter_mcu_pipeline_template_v2.sv new file mode 100644 index 0000000..2955d4c --- /dev/null +++ b/otter_mcu_pipeline_template_v2.sv @@ -0,0 +1,149 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: J. Callenes +// +// Create Date: 01/04/2019 04:32:12 PM +// Design Name: +// Module Name: PIPELINED_OTTER_CPU +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + typedef enum logic [6:0] { + LUI = 7'b0110111, + AUIPC = 7'b0010111, + JAL = 7'b1101111, + JALR = 7'b1100111, + BRANCH = 7'b1100011, + LOAD = 7'b0000011, + STORE = 7'b0100011, + OP_IMM = 7'b0010011, + OP = 7'b0110011, + SYSTEM = 7'b1110011 + } opcode_t; + +typedef struct packed{ + opcode_t opcode; + logic [4:0] rs1_addr; + logic [4:0] rs2_addr; + logic [4:0] rd_addr; + logic rs1_used; + logic rs2_used; + logic rd_used; + logic [3:0] alu_fun; + logic memWrite; + logic memRead2; + logic regWrite; + logic [1:0] rf_wr_sel; + logic [2:0] mem_type; //sign, size + logic [31:0] pc; +} instr_t; + +module OTTER_MCU(input CLK, + input INTR, + input RESET, + input [31:0] IOBUS_IN, + output [31:0] IOBUS_OUT, + output [31:0] IOBUS_ADDR, + output logic IOBUS_WR +); + wire [6:0] opcode; + wire [31:0] pc, pc_value, next_pc, jalr_pc, branch_pc, jump_pc, int_pc,A,B, + I_immed,S_immed,U_immed,aluBin,aluAin,aluResult,rfIn,csr_reg, mem_data; + + wire [31:0] IR; + wire memRead1,memRead2; + + wire pcWrite,regWrite,memWrite, op1_sel,mem_op,IorD,pcWriteCond,memRead; + wire [1:0] opB_sel, rf_sel, wb_sel, mSize; + logic [1:0] pc_sel; + wire [3:0]alu_fun; + wire opA_sel; + + logic br_lt,br_eq,br_ltu; + +//==== Instruction Fetch =========================================== + + logic [31:0] if_de_pc; + + always_ff @(posedge CLK) begin + if_de_pc <= pc; + end + + assign pcWrite = 1'b1; //Hardwired high, assuming now hazards + assign memRead1 = 1'b1; //Fetch new instruction every cycle + + + + + + + +//==== Instruction Decode =========================================== + logic [31:0] de_ex_opA; + logic [31:0] de_ex_opB; + logic [31:0] de_ex_rs2; + + instr_t de_ex_inst, de_inst; + + opcode_t OPCODE; + assign OPCODE_t = opcode_t'(opcode); + + assign de_inst.rs1_addr=IR[19:15]; + assign de_inst.rs2_addr=IR[24:20]; + assign de_inst.rd_addr=IR[11:7]; + assign de_inst.opcode=OPCODE; + + assign de_inst.rs1_used= de_inst.rs1 != 0 + && de_inst.opcode != LUI + && de_inst.opcode != AUIPC + && de_inst.opcode != JAL; + + + + + +//==== Execute ====================================================== + logic [31:0] ex_mem_rs2; + logic ex_mem_aluRes = 0; + instr_t ex_mem_inst; + logic [31:0] opA_forwarded; + logic [31:0] opB_forwarded; + + // Creates a RISC-V ALU + OTTER_ALU ALU (de_ex_inst.alu_fun, de_ex_opA, de_ex_opB, aluResult); // the ALU + + + + + +//==== Memory ====================================================== + + + assign IOBUS_ADDR = ex_mem_aluRes; + assign IOBUS_OUT = ex_mem_rs2; + + + + + +//==== Write Back ================================================== + + + + + + + + +endmodule diff --git a/otter_memory_v1_07.sv b/otter_memory_v1_07.sv new file mode 100644 index 0000000..a5bd727 --- /dev/null +++ b/otter_memory_v1_07.sv @@ -0,0 +1,158 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: J. Callenes, P. Hummel +// +// Create Date: 01/27/2019 08:37:11 AM +// Module Name: OTTER_mem +// Project Name: Memory for OTTER RV32I RISC-V +// Tool Versions: Xilinx Vivado 2019.2 +// Description: 64k Memory, dual access read single access write. Designed to +// purposely utilize BRAM which requires synchronous reads and write +// ADDR1 used for Program Memory Instruction. Word addressable so it +// must be adapted from byte addresses in connection from PC +// ADDR2 used for data access, both internal and external memory +// mapped IO. ADDR2 is byte addressable. +// RDEN1 and EDEN2 are read enables for ADDR1 and ADDR2. These are +// needed due to synchronous reading +// MEM_SIZE used to specify reads as byte (0), half (1), or word (2) +// MEM_SIGN used to specify unsigned (1) vs signed (0) extension +// IO_IN is data from external IO and synchronously buffered +// +// Memory OTTER_MEMORY ( +// .MEM_CLK (), +// .MEM_RDEN1 (), +// .MEM_RDEN2 (), +// .MEM_WE2 (), +// .MEM_ADDR1 (), +// .MEM_ADDR2 (), +// .MEM_DIN2 (), +// .MEM_SIZE (), +// .MEM_SIGN (), +// .IO_IN (), +// .IO_WR (), +// .MEM_DOUT1 (), +// .MEM_DOUT2 () ); +// +// Revision: +// Revision 0.01 - Original by J. Callenes +// Revision 1.02 - Rewrite to simplify logic by P. Hummel +// Revision 1.03 - changed signal names, added instantiation template +// Revision 1.04 - added defualt to write case statement +// Revision 1.05 - changed MEM_WD to MEM_DIN2, changed default to save nothing +// Revision 1.06 - removed typo in instantiation template +// Revision 1.07 - remove unused wordAddr1 signal +// +////////////////////////////////////////////////////////////////////////////////// + + module Memory ( + input MEM_CLK, + input MEM_RDEN1, // read enable Instruction + input MEM_RDEN2, // read enable data + input MEM_WE2, // write enable. + input [13:0] MEM_ADDR1, // Instruction Memory word Addr (Connect to PC[15:2]) + input [31:0] MEM_ADDR2, // Data Memory Addr + input [31:0] MEM_DIN2, // Data to save + input [1:0] MEM_SIZE, // 0-Byte, 1-Half, 2-Word + input MEM_SIGN, // 1-unsigned 0-signed + input [31:0] IO_IN, // Data from IO + //output ERR, // only used for testing + output logic IO_WR, // IO 1-write 0-read + output logic [31:0] MEM_DOUT1, // Instruction + output logic [31:0] MEM_DOUT2); // Data + + logic [13:0] wordAddr2; + logic [31:0] memReadWord, ioBuffer, memReadSized; + logic [1:0] byteOffset; + logic weAddrValid; // active when saving (WE) to valid memory address + + (* rom_style="{distributed | block}" *) + (* ram_decomp = "power" *) logic [31:0] memory [0:16383]; + + initial begin + $readmemh("otter_multi.mem", memory, 0, 16383); + end + + assign wordAddr2 = MEM_ADDR2[15:2]; + assign byteOffset = MEM_ADDR2[1:0]; // byte offset of memory address + + // NOT USED IN OTTER + //Check for misalligned or out of bounds memory accesses + //assign ERR = ((MEM_ADDR1 >= 2**ACTUAL_WIDTH)|| (MEM_ADDR2 >= 2**ACTUAL_WIDTH) + // || MEM_ADDR1[1:0] != 2'b0 || MEM_ADDR2[1:0] !=2'b0)? 1 : 0; + + // buffer the IO input for reading + always_ff @(posedge MEM_CLK) begin + if(MEM_RDEN2) + ioBuffer <= IO_IN; + end + + // BRAM requires all reads and writes to occur synchronously + always_ff @(posedge MEM_CLK) begin + + // save data (WD) to memory (ADDR2) + if (weAddrValid == 1) begin // write enable and valid address space + case({MEM_SIZE,byteOffset}) + 4'b0000: memory[wordAddr2][7:0] <= MEM_DIN2[7:0]; // sb at byte offsets + 4'b0001: memory[wordAddr2][15:8] <= MEM_DIN2[7:0]; + 4'b0010: memory[wordAddr2][23:16] <= MEM_DIN2[7:0]; + 4'b0011: memory[wordAddr2][31:24] <= MEM_DIN2[7:0]; + 4'b0100: memory[wordAddr2][15:0] <= MEM_DIN2[15:0]; // sh at byte offsets + 4'b0101: memory[wordAddr2][23:8] <= MEM_DIN2[15:0]; + 4'b0110: memory[wordAddr2][31:16] <= MEM_DIN2[15:0]; + 4'b1000: memory[wordAddr2] <= MEM_DIN2; // sw + //default: memory[wordAddr2] <= 32'b0 // unsupported size, byte offset + // removed to avoid mistakes causing memory to be zeroed. + endcase + end + + // read all data synchronously required for BRAM + if (MEM_RDEN1) // need EN for extra load cycle to not change instruction + MEM_DOUT1 <= memory[MEM_ADDR1]; + + if (MEM_RDEN2) // Read word from memory + memReadWord <= memory[wordAddr2]; + end + + // Change the data word into sized bytes and sign extend + always_comb begin + case({MEM_SIGN,MEM_SIZE,byteOffset}) + 5'b00011: memReadSized = {{24{memReadWord[31]}},memReadWord[31:24]}; // signed byte + 5'b00010: memReadSized = {{24{memReadWord[23]}},memReadWord[23:16]}; + 5'b00001: memReadSized = {{24{memReadWord[15]}},memReadWord[15:8]}; + 5'b00000: memReadSized = {{24{memReadWord[7]}},memReadWord[7:0]}; + + 5'b00110: memReadSized = {{16{memReadWord[31]}},memReadWord[31:16]}; // signed half + 5'b00101: memReadSized = {{16{memReadWord[23]}},memReadWord[23:8]}; + 5'b00100: memReadSized = {{16{memReadWord[15]}},memReadWord[15:0]}; + + 5'b01000: memReadSized = memReadWord; // word + + 5'b10011: memReadSized = {24'd0,memReadWord[31:24]}; // unsigned byte + 5'b10010: memReadSized = {24'd0,memReadWord[23:16]}; + 5'b10001: memReadSized = {24'd0,memReadWord[15:8]}; + 5'b10000: memReadSized = {24'd0,memReadWord[7:0]}; + + 5'b10110: memReadSized = {16'd0,memReadWord[31:16]}; // unsigned half + 5'b10101: memReadSized = {16'd0,memReadWord[23:8]}; + 5'b10100: memReadSized = {16'd0,memReadWord[15:0]}; + + default: memReadSized = 32'b0; // unsupported size, byte offset combination + endcase + end + + // Memory Mapped IO + always_comb begin + if(MEM_ADDR2 >= 32'h00010000) begin // external address range + IO_WR = MEM_WE2; // IO Write + MEM_DOUT2 = ioBuffer; // IO read from buffer + weAddrValid = 0; // address beyond memory range + end + else begin + IO_WR = 0; // not MMIO + MEM_DOUT2 = memReadSized; // output sized and sign extended data + weAddrValid = MEM_WE2; // address in valid memory range + end + end + + endmodule diff --git a/otter_multi.mem b/otter_multi.mem new file mode 100644 index 0000000..12a1dec --- /dev/null +++ b/otter_multi.mem @@ -0,0 +1,2 @@ +01e00093 +00007133