diff --git a/wally-pipelined/src/dmem/dmem.sv b/wally-pipelined/src/dmem/dmem.sv index 1442b93c3..588739320 100644 --- a/wally-pipelined/src/dmem/dmem.sv +++ b/wally-pipelined/src/dmem/dmem.sv @@ -29,7 +29,7 @@ module dmem ( input logic clk, reset, - input logic FlushW, + input logic StallW, FlushW, //output logic DataStall, // Memory Stage input logic [1:0] MemRWM, @@ -37,34 +37,38 @@ module dmem ( input logic [2:0] Funct3M, //input logic [`XLEN-1:0] ReadDataW, input logic [`XLEN-1:0] WriteDataM, + input logic AtomicM, output logic [`XLEN-1:0] MemPAdrM, output logic MemReadM, MemWriteM, output logic DataMisalignedM, // Writeback Stage input logic MemAckW, input logic [`XLEN-1:0] ReadDataW, + output logic SquashSCW, // faults input logic DataAccessFaultM, output logic LoadMisalignedFaultM, LoadAccessFaultM, output logic StoreMisalignedFaultM, StoreAccessFaultM ); + logic SquashSCM; + // Initially no MMU assign MemPAdrM = MemAdrM; // Determine if an Unaligned access is taking place always_comb case(Funct3M[1:0]) - 2'b00: DataMisalignedM = 0; // lb, sb, lbu - 2'b01: DataMisalignedM = MemAdrM[0]; // lh, sh, lhu + 2'b00: DataMisalignedM = 0; // lb, sb, lbu + 2'b01: DataMisalignedM = MemAdrM[0]; // lh, sh, lhu 2'b10: DataMisalignedM = MemAdrM[1] | MemAdrM[0]; // lw, sw, flw, fsw, lwu - 2'b11: DataMisalignedM = |MemAdrM[2:0]; // ld, sd, fld, fsd + 2'b11: DataMisalignedM = |MemAdrM[2:0]; // ld, sd, fld, fsd endcase - // Squash unaligned data accesses + // Squash unaligned data accesses and failed store conditionals // *** this is also the place to squash if the cache is hit assign MemReadM = MemRWM[1] & ~DataMisalignedM; - assign MemWriteM = MemRWM[0] & ~DataMisalignedM; + assign MemWriteM = MemRWM[0] & ~DataMisalignedM && ~SquashSCM; // Determine if address is valid assign LoadMisalignedFaultM = DataMisalignedM & MemRWM[1]; @@ -72,6 +76,31 @@ module dmem ( assign StoreMisalignedFaultM = DataMisalignedM & MemRWM[0]; assign StoreAccessFaultM = DataAccessFaultM & MemRWM[0]; + // Handle atomic load reserved / store conditional + generate + if (`A_SUPPORTED) begin // atomic instructions supported + logic [`XLEN-1:2] ReservationPAdrW; + logic ReservationValidM, ReservationValidW; + logic lrM, scM, WriteAdrMatchM; + + assign lrM = MemReadM && AtomicM; + assign scM = MemRWM[0] && AtomicM; + assign WriteAdrMatchM = MemRWM[0] && (MemPAdrM == ReservationPAdrW) && ReservationValidW; + assign SquashSCM = scM && ~WriteAdrMatchM; + always_comb begin // ReservationValidM (next valiue of valid reservation) + if (lrM) ReservationValidM = 1; // set valid on load reserve + else if (scM || WriteAdrMatchM) ReservationValidM = 0; // clear valid on store to same address or any sc + else ReservationValidM = ReservationValidW; // otherwise don't change valid + end + flopenrc #(`XLEN-2) resadrreg(clk, reset, FlushW, ~StallW && lrM, MemPAdrM[`XLEN-1:2], ReservationPAdrW); // could drop clear on this one but not valid + flopenrc #(1) resvldreg(clk, reset, FlushW, ~StallW, ReservationValidM, ReservationValidW); + flopenrc #(1) squashreg(clk, reset, FlushW, ~StallW, SquashSCM, SquashSCW); + end else begin // Atomic operations not supported + assign SquashSCM = 0; + assign SquashSCW = 0; + end + endgenerate + // Data stall //assign DataStall = 0; diff --git a/wally-pipelined/src/generic/mux.sv b/wally-pipelined/src/generic/mux.sv index afa0a1250..6621662d8 100644 --- a/wally-pipelined/src/generic/mux.sv +++ b/wally-pipelined/src/generic/mux.sv @@ -59,4 +59,12 @@ module mux5 #(parameter WIDTH = 8) ( assign y = s[2] ? d4 : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0)); endmodule +module mux6 #(parameter WIDTH = 8) ( + input logic [WIDTH-1:0] d0, d1, d2, d3, d4, d5, + input logic [2:0] s, + output logic [WIDTH-1:0] y); + + assign y = s[2] ? (s[0] ? d5 : d4) : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0)); +endmodule + /* verilator lint_on DECLFILENAME */ diff --git a/wally-pipelined/src/ieu/controller.sv b/wally-pipelined/src/ieu/controller.sv index a917bbb60..663a24c53 100644 --- a/wally-pipelined/src/ieu/controller.sv +++ b/wally-pipelined/src/ieu/controller.sv @@ -47,6 +47,7 @@ module controller( input logic StallM, FlushM, output logic [1:0] MemRWM, output logic CSRReadM, CSRWriteM, PrivilegedM, + output logic AtomicM, output logic [2:0] Funct3M, output logic RegWriteM, // for Hazard Unit // Writeback stage control signals @@ -75,10 +76,11 @@ module controller( logic TargetSrcD, W64D, MulDivD; logic CSRZeroSrcD; logic CSRReadD; + logic AtomicD, AtomicE; logic CSRWriteD, CSRWriteE; logic InstrValidE, InstrValidM; logic PrivilegedD, PrivilegedE; - logic [20:0] ControlsD; + logic [21:0] ControlsD; logic aluc3D; logic subD, sraD, sltD, sltuD; logic BranchTakenE; @@ -97,38 +99,48 @@ module controller( generate always_comb case(OpD) - // RegWrite_ImmSrc_ALUSrc_MemRW_ResultSrc_Branch_ALUOp_Jump_TargetSrc_W64_CSRRead_Privileged_MulDiv_Illegal - 7'b0000011: ControlsD = 21'b1_000_01_10_001_0_00_0_0_0_0_0_0_0; // lw - 7'b0100011: ControlsD = 21'b0_001_01_01_000_0_00_0_0_0_0_0_0_0; // sw - 7'b0110011: if (Funct7D == 7'b0000000 || Funct7D == 7'b0100000) - ControlsD = 21'b1_000_00_00_000_0_10_0_0_0_0_0_0_0; // R-type - else if (Funct7D == 7'b0000001 && `M_SUPPORTED) - ControlsD = 21'b1_000_00_00_100_0_00_0_0_0_0_0_1_0; // Multiply/Divide - else - ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction - 7'b0111011: if ((Funct7D == 7'b0000000 || Funct7D == 7'b0100000) && `XLEN == 64) - ControlsD = 21'b1_000_00_00_000_0_10_0_0_1_0_0_0_0; // R-type W instructions for RV64i - else if (Funct7D == 7'b0000001 && `M_SUPPORTED && `XLEN == 64) - ControlsD = 21'b1_000_00_00_100_0_00_0_0_1_0_0_1_0; // W-type Multiply/Divide - else - ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction - 7'b1100011: ControlsD = 21'b0_010_00_00_000_1_01_0_0_0_0_0_0_0; // beq - 7'b0010011: ControlsD = 21'b1_000_01_00_000_0_10_0_0_0_0_0_0_0; // I-type ALU + // *** Atomic p. 132 assembly encodings, defs 48 + // RegWrite_ImmSrc_ALUSrc_MemRW_ResultSrc_Branch_ALUOp_Jump_TargetSrc_W64_CSRRead_Privileged_MulDiv_Atomic_Illegal + 7'b0000000: ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // illegal instruction + 7'b0000011: ControlsD = 22'b1_000_01_10_001_0_00_0_0_0_0_0_0_0_0; // lw + 7'b0001111: ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_0; // fence = nop + 7'b0010011: ControlsD = 22'b1_000_01_00_000_0_10_0_0_0_0_0_0_0_0; // I-type ALU + 7'b0010111: ControlsD = 22'b1_100_11_00_000_0_00_0_0_0_0_0_0_0_0; // auipc 7'b0011011: if (`XLEN == 64) - ControlsD = 21'b1_000_01_00_000_0_10_0_0_1_0_0_0_0; // IW-type ALU for RV64i + ControlsD = 22'b1_000_01_00_000_0_10_0_0_1_0_0_0_0_0; // IW-type ALU for RV64i else - ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction - 7'b1101111: ControlsD = 21'b1_011_00_00_010_0_00_1_0_0_0_0_0_0; // jal - 7'b1100111: ControlsD = 21'b1_000_00_00_010_0_00_1_1_0_0_0_0_0; // jalr - 7'b0010111: ControlsD = 21'b1_100_11_00_000_0_00_0_0_0_0_0_0_0; // auipc - 7'b0110111: ControlsD = 21'b1_100_01_00_000_0_11_0_0_0_0_0_0_0; // lui - 7'b0001111: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_0; // fence = nop + ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction + 7'b0100011: ControlsD = 22'b0_001_01_01_000_0_00_0_0_0_0_0_0_0_0; // sw + 7'b0101111: if (`A_SUPPORTED) begin + if (InstrD[31:27] == 5'b00010) + ControlsD = 22'b1_000_00_10_001_0_00_0_0_0_0_0_0_1_0; // lr + else if (InstrD[31:27] == 5'b00011) + ControlsD = 22'b1_101_01_01_110_0_00_0_0_0_0_0_0_1_0; // sc + else + ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_1_0; // other atomic; decode later + end else + ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction + 7'b0110011: if (Funct7D == 7'b0000000 || Funct7D == 7'b0100000) + ControlsD = 22'b1_000_00_00_000_0_10_0_0_0_0_0_0_0_0; // R-type + else if (Funct7D == 7'b0000001 && `M_SUPPORTED) + ControlsD = 22'b1_000_00_00_100_0_00_0_0_0_0_0_1_0_0; // Multiply/Divide + else + ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction + 7'b0110111: ControlsD = 22'b1_100_01_00_000_0_11_0_0_0_0_0_0_0_0; // lui + 7'b0111011: if ((Funct7D == 7'b0000000 || Funct7D == 7'b0100000) && `XLEN == 64) + ControlsD = 22'b1_000_00_00_000_0_10_0_0_1_0_0_0_0_0; // R-type W instructions for RV64i + else if (Funct7D == 7'b0000001 && `M_SUPPORTED && `XLEN == 64) + ControlsD = 22'b1_000_00_00_100_0_00_0_0_1_0_0_1_0_0; // W-type Multiply/Divide + else + ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction + 7'b1100011: ControlsD = 22'b0_010_00_00_000_1_01_0_0_0_0_0_0_0_0; // beq + 7'b1100111: ControlsD = 22'b1_000_00_00_010_0_00_1_1_0_0_0_0_0_0; // jalr + 7'b1101111: ControlsD = 22'b1_011_00_00_010_0_00_1_0_0_0_0_0_0_0; // jal 7'b1110011: if (Funct3D == 3'b000) - ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_1_0_0; // privileged; decoded further in priveleged modules + ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_1_0_0_0; // privileged; decoded further in priveleged modules else - ControlsD = 21'b1_000_00_00_011_0_00_0_0_0_1_0_0_0; // csrs - 7'b0000000: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // illegal instruction - default: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction + ControlsD = 22'b1_000_00_00_011_0_00_0_0_0_1_0_0_0_0; // csrs + default: ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction endcase endgenerate @@ -137,7 +149,7 @@ module controller( assign IllegalBaseInstrFaultD = ControlsD[0]; assign {RegWriteD, ImmSrcD, ALUSrcAD, ALUSrcBD, MemRWD, ResultSrcD, BranchD, ALUOpD, JumpD, TargetSrcD, W64D, CSRReadD, - PrivilegedD, MulDivD, unused} = ControlsD & ~IllegalIEUInstrFaultD; + PrivilegedD, MulDivD, AtomicD, unused} = ControlsD & ~IllegalIEUInstrFaultD; // *** move Privileged, CSRwrite?? Or move controller out of IEU into datapath and handle all instructions assign CSRZeroSrcD = InstrD[14] ? (InstrD[19:15] == 0) : (Rs1D == 0); // Is a CSR instruction using zero as the source? @@ -160,9 +172,9 @@ module controller( endcase // Execute stage pipeline control register and logic - flopenrc #(25) controlregE(clk, reset, FlushE, ~StallE, - {RegWriteD, ResultSrcD, MemRWD, JumpD, BranchD, ALUControlD, ALUSrcAD, ALUSrcBD, TargetSrcD, CSRReadD, CSRWriteD, PrivilegedD, Funct3D, W64D, MulDivD, 1'b1}, - {RegWriteE, ResultSrcE, MemRWE, JumpE, BranchE, ALUControlE, ALUSrcAE, ALUSrcBE, TargetSrcE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, W64E, MulDivE, InstrValidE}); + flopenrc #(26) controlregE(clk, reset, FlushE, ~StallE, + {RegWriteD, ResultSrcD, MemRWD, JumpD, BranchD, ALUControlD, ALUSrcAD, ALUSrcBD, TargetSrcD, CSRReadD, CSRWriteD, PrivilegedD, Funct3D, W64D, MulDivD, AtomicD, 1'b1}, + {RegWriteE, ResultSrcE, MemRWE, JumpE, BranchE, ALUControlE, ALUSrcAE, ALUSrcBE, TargetSrcE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, W64E, MulDivE, AtomicE, InstrValidE}); // Branch Logic assign {zeroE, ltE, ltuE} = FlagsE; @@ -183,9 +195,9 @@ module controller( assign MemReadE = MemRWE[1]; // Memory stage pipeline control register - flopenrc #(13) controlregM(clk, reset, FlushM, ~StallM, - {RegWriteE, ResultSrcE, MemRWE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, InstrValidE}, - {RegWriteM, ResultSrcM, MemRWM, CSRReadM, CSRWriteM, PrivilegedM, Funct3M, InstrValidM}); + flopenrc #(14) controlregM(clk, reset, FlushM, ~StallM, + {RegWriteE, ResultSrcE, MemRWE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, AtomicE, InstrValidE}, + {RegWriteM, ResultSrcM, MemRWM, CSRReadM, CSRWriteM, PrivilegedM, Funct3M, AtomicM, InstrValidM}); // Writeback stage pipeline control register flopenrc #(5) controlregW(clk, reset, FlushW, ~StallW, diff --git a/wally-pipelined/src/ieu/datapath.sv b/wally-pipelined/src/ieu/datapath.sv index 022cc6259..f8e356d3f 100644 --- a/wally-pipelined/src/ieu/datapath.sv +++ b/wally-pipelined/src/ieu/datapath.sv @@ -47,9 +47,10 @@ module datapath ( // Writeback stage signals input logic StallW, FlushW, input logic RegWriteW, + input logic SquashSCW, input logic [2:0] ResultSrcW, input logic [`XLEN-1:0] PCLinkW, - input logic [`XLEN-1:0] CSRReadValW, ReadDataW, MulDivResultW, + input logic [`XLEN-1:0] CSRReadValW, ReadDataW, MulDivResultW, // Hazard Unit signals output logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, output logic [4:0] RdE, RdM, RdW @@ -70,6 +71,7 @@ module datapath ( // Memory stage signals logic [`XLEN-1:0] ALUResultM; // Writeback stage signals + logic [`XLEN-1:0] SCResultW; logic [`XLEN-1:0] ALUResultW; logic [`XLEN-1:0] ResultW; @@ -107,5 +109,13 @@ module datapath ( flopenrc #(`XLEN) ALUResultWReg(clk, reset, FlushW, ~StallW, ALUResultM, ALUResultW); flopenrc #(5) RdWEg(clk, reset, FlushW, ~StallW, RdM, RdW); - mux5 #(`XLEN) resultmux(ALUResultW, ReadDataW, PCLinkW, CSRReadValW, MulDivResultW, ResultSrcW, ResultW); + // handle Store Conditional result if atomic extension supported + generate + if (`A_SUPPORTED) + assign SCResultW = SquashSCW ? {{(`XLEN-1){1'b0}}, 1'b1} : {{(`XLEN-1){1'b0}}, 1'b0}; + else + assign SCResultW = 0; + endgenerate + + mux6 #(`XLEN) resultmux(ALUResultW, ReadDataW, PCLinkW, CSRReadValW, MulDivResultW, SCResultW, ResultSrcW, ResultW); endmodule diff --git a/wally-pipelined/src/ieu/extend.sv b/wally-pipelined/src/ieu/extend.sv index 243dced3d..8d79b0a3f 100644 --- a/wally-pipelined/src/ieu/extend.sv +++ b/wally-pipelined/src/ieu/extend.sv @@ -29,19 +29,26 @@ module extend ( input logic [31:7] InstrD, input logic [2:0] ImmSrcD, output logic [`XLEN-1:0 ] ExtImmD); + + logic [`XLEN-1:0] undefined = {(`XLEN){1'bx}}; // could change to 0 after debug - always_comb - case(ImmSrcD) - // I-type - 3'b000: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:20]}; - // S-type (stores) - 3'b001: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:25], InstrD[11:7]}; - // B-type (branches) - 3'b010: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[7], InstrD[30:25], InstrD[11:8], 1'b0}; - // J-type (jal) - 3'b011: ExtImmD = {{(`XLEN-20){InstrD[31]}}, InstrD[19:12], InstrD[20], InstrD[30:21], 1'b0}; - // U-type (lui, auipc) - 3'b100: ExtImmD = {{(`XLEN-31){InstrD[31]}}, InstrD[30:12], 12'b0}; - default: ExtImmD = {(`XLEN-1){1'bx}}; // undefined - endcase + generate + always_comb + case(ImmSrcD) + // I-type + 3'b000: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:20]}; + // S-type (stores) + 3'b001: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:25], InstrD[11:7]}; + // B-type (branches) + 3'b010: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[7], InstrD[30:25], InstrD[11:8], 1'b0}; + // J-type (jal) + 3'b011: ExtImmD = {{(`XLEN-20){InstrD[31]}}, InstrD[19:12], InstrD[20], InstrD[30:21], 1'b0}; + // U-type (lui, auipc) + 3'b100: ExtImmD = {{(`XLEN-31){InstrD[31]}}, InstrD[30:12], 12'b0}; + // Store Conditional: zero offset + 3'b101: if (`A_SUPPORTED) ExtImmD = 0; + else ExtImmD = undefined; + default: ExtImmD = undefined; // undefined + endcase + endgenerate endmodule diff --git a/wally-pipelined/src/ieu/ieu.sv b/wally-pipelined/src/ieu/ieu.sv index 29ffb497e..34787236d 100644 --- a/wally-pipelined/src/ieu/ieu.sv +++ b/wally-pipelined/src/ieu/ieu.sv @@ -40,7 +40,9 @@ module ieu ( // Memory stage interface input logic DataMisalignedM, input logic DataAccessFaultM, + input logic SquashSCW, output logic [1:0] MemRWM, + output logic AtomicM, output logic [`XLEN-1:0] MemAdrM, WriteDataM, output logic [`XLEN-1:0] SrcAM, output logic [2:0] Funct3M, diff --git a/wally-pipelined/src/wally/wallypipelinedhart.sv b/wally-pipelined/src/wally/wallypipelinedhart.sv index 793eafb29..1628809db 100644 --- a/wally-pipelined/src/wally/wallypipelinedhart.sv +++ b/wally-pipelined/src/wally/wallypipelinedhart.sv @@ -60,7 +60,7 @@ module wallypipelinedhart ( // new signals that must connect through DP logic MulDivE, W64E; - logic CSRReadM, CSRWriteM, PrivilegedM; + logic CSRReadM, CSRWriteM, PrivilegedM, AtomicM; logic [`XLEN-1:0] SrcAE, SrcBE; logic [`XLEN-1:0] SrcAM; logic [2:0] Funct3E; @@ -85,6 +85,7 @@ module wallypipelinedhart ( logic [4:0] SetFflagsM; logic [2:0] FRM_REGW; logic FloatRegWriteW; + logic SquashSCW; // bus interface to dmem logic MemReadM, MemWriteM; diff --git a/wally-pipelined/testbench/testbench-imperas.sv b/wally-pipelined/testbench/testbench-imperas.sv index e121c4603..e810eae83 100644 --- a/wally-pipelined/testbench/testbench-imperas.sv +++ b/wally-pipelined/testbench/testbench-imperas.sv @@ -90,7 +90,6 @@ string tests64iNOc[] = { "rv64i/I-MISALIGN_JMP-01","2000" }; string tests64i[] = '{ - "rv64i/I-MISALIGN_LDST-01", "2010", "rv64i/I-ADD-01", "3000", "rv64i/I-ADDI-01", "3000", "rv64i/I-ADDIW-01", "3000",