From 2d408981587280bbcd075c281794d74c0cfa3aa7 Mon Sep 17 00:00:00 2001 From: Teo Ene Date: Sun, 28 Feb 2021 22:22:04 -0600 Subject: [PATCH 01/13] Properly implemented the fix from commit 5fee65231e13f7b7fe3561980c32542b835bf0ac --- wally-pipelined/src/uncore/imem.sv | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/wally-pipelined/src/uncore/imem.sv b/wally-pipelined/src/uncore/imem.sv index 86d235564..9aa37e49e 100644 --- a/wally-pipelined/src/uncore/imem.sv +++ b/wally-pipelined/src/uncore/imem.sv @@ -53,19 +53,11 @@ module imem ( generate if (`XLEN==32) begin assign InstrF = AdrF[1] ? {rd2[15:0], rd[31:16]} : rd; - if(`TIMBASE==0) begin - assign InstrAccessFaultF = 0; - end else begin - assign InstrAccessFaultF = ~AdrF[31] | (|AdrF[30:16]); // memory mapped to 0x80000000-0x8000FFFF - end + assign InstrAccessFaultF = ~&(({AdrF,0} ~^ `TIMBASE) | `TIMRANGE); end else begin assign InstrF = AdrF[2] ? (AdrF[1] ? {rd2[15:0], rd[63:48]} : rd[63:32]) : (AdrF[1] ? rd[47:16] : rd[31:0]); - if(`TIMBASE==0) begin - assign InstrAccessFaultF = 0; - end else begin - assign InstrAccessFaultF = (|AdrF[`XLEN-1:32]) | ~AdrF[31] | (|AdrF[30:16]); // memory mapped to 0x80000000-0x8000FFFF] - end + assign InstrAccessFaultF = |AdrF[`XLEN-1:32] | ~&({AdrF[31:1],1'b0} ~^ `TIMBASE | `TIMRANGE); end endgenerate endmodule From 6f4e8b723e627d229cfbeba65efbd8b4b3f6309b Mon Sep 17 00:00:00 2001 From: David Harris Date: Mon, 1 Mar 2021 00:09:45 -0500 Subject: [PATCH 02/13] Initial (untested) implementation of lr and sc --- wally-pipelined/src/dmem/dmem.sv | 41 +++++++-- wally-pipelined/src/generic/mux.sv | 8 ++ wally-pipelined/src/ieu/controller.sv | 84 +++++++++++-------- wally-pipelined/src/ieu/datapath.sv | 14 +++- wally-pipelined/src/ieu/extend.sv | 35 ++++---- wally-pipelined/src/ieu/ieu.sv | 2 + .../src/wally/wallypipelinedhart.sv | 3 +- .../testbench/testbench-imperas.sv | 1 - 8 files changed, 128 insertions(+), 60 deletions(-) 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", From d02e22feacb0b8a97340d69e538d579ae1e5928c Mon Sep 17 00:00:00 2001 From: Teo Ene Date: Tue, 2 Mar 2021 17:23:39 -0600 Subject: [PATCH 03/13] Updated coremark .do file for easier debugging --- wally-pipelined/regression/wally-coremark.do | 57 ++++++++++---------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/wally-pipelined/regression/wally-coremark.do b/wally-pipelined/regression/wally-coremark.do index d56122384..186bbf724 100644 --- a/wally-pipelined/regression/wally-coremark.do +++ b/wally-pipelined/regression/wally-coremark.do @@ -43,46 +43,47 @@ add wave /testbench/clk add wave /testbench/reset add wave -divider #add wave /testbench/dut/hart/ebu/IReadF -add wave /testbench/dut/hart/DataStall -add wave /testbench/dut/hart/InstrStall -add wave /testbench/dut/hart/StallF -add wave /testbench/dut/hart/StallD -add wave /testbench/dut/hart/FlushD -add wave /testbench/dut/hart/FlushE -add wave /testbench/dut/hart/FlushM -add wave /testbench/dut/hart/FlushW +#add wave /testbench/dut/hart/DataStall +#add wave /testbench/dut/hart/InstrStall +#add wave /testbench/dut/hart/StallF +#add wave /testbench/dut/hart/StallD +#add wave /testbench/dut/hart/FlushD +#add wave /testbench/dut/hart/FlushE +#add wave /testbench/dut/hart/FlushM +#add wave /testbench/dut/hart/FlushW add wave -divider add wave -hex /testbench/dut/hart/ifu/PCF add wave -hex /testbench/dut/hart/ifu/InstrF add wave /testbench/InstrFName -#add wave -hex /testbench/dut/hart/ifu/PCD +add wave -hex /testbench/dut/hart/ifu/PCD add wave -hex /testbench/dut/hart/ifu/InstrD add wave /testbench/InstrDName add wave -divider -#add wave -hex /testbench/dut/hart/ifu/PCE -#add wave -hex /testbench/dut/hart/ifu/InstrE +add wave -hex /testbench/dut/hart/ifu/PCE +add wave -hex /testbench/dut/hart/ifu/InstrE add wave /testbench/InstrEName -add wave -hex /testbench/dut/hart/ieu/dp/SrcAE -add wave -hex /testbench/dut/hart/ieu/dp/SrcBE -add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE -add wave /testbench/dut/hart/ieu/dp/PCSrcE +#add wave -hex /testbench/dut/hart/ieu/dp/SrcAE +#add wave -hex /testbench/dut/hart/ieu/dp/SrcBE +#add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE +#add wave /testbench/dut/hart/ieu/dp/PCSrcE add wave -divider #add wave -hex /testbench/dut/hart/ifu/PCM #add wave -hex /testbench/dut/hart/ifu/InstrM -add wave /testbench/InstrMName -add wave /testbench/dut/uncore/dtim/memwrite -add wave -hex /testbench/dut/uncore/HADDR -add wave -hex /testbench/dut/uncore/HWDATA +#add wave /testbench/InstrMName +#add wave /testbench/dut/uncore/dtim/memwrite +#add wave -hex /testbench/dut/uncore/HADDR +#add wave -hex /testbench/dut/uncore/HWDATA +#add wave -divider +#add wave -hex /testbench/dut/hart/ifu/PCW +#add wave /testbench/InstrWName +#add wave /testbench/dut/hart/ieu/dp/RegWriteW +#add wave -hex /testbench/dut/hart/ieu/dp/ResultW +#add wave -hex /testbench/dut/hart/ieu/dp/RdW +#add wave -hex -r /testbench/* +add wave -hex -r /testbench/dut/hart/ieu/dp/regf/* add wave -divider -add wave -hex /testbench/dut/hart/ifu/PCW -add wave /testbench/InstrWName -add wave /testbench/dut/hart/ieu/dp/RegWriteW -add wave -hex /testbench/dut/hart/ieu/dp/ResultW -add wave -hex /testbench/dut/hart/ieu/dp/RdW add wave -divider -#add ww -add wave -hex -r /testbench/* -- Set Wave Output Items TreeUpdate [SetDefaultTree] @@ -98,6 +99,6 @@ configure wave -childrowmargin 2 set DefaultRadix hexadecimal -- Run the Simulation -#run 1000 -run -all +run 3000 +#run -all #quit From b50faef94d64b8ba31ab7686612b0f63f63475a4 Mon Sep 17 00:00:00 2001 From: Teo Ene Date: Wed, 3 Mar 2021 15:10:39 -0600 Subject: [PATCH 04/13] Updated coremark .do file for easier debugging --- wally-pipelined/regression/wally-coremark.do | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/wally-pipelined/regression/wally-coremark.do b/wally-pipelined/regression/wally-coremark.do index 186bbf724..056b34cb7 100644 --- a/wally-pipelined/regression/wally-coremark.do +++ b/wally-pipelined/regression/wally-coremark.do @@ -56,6 +56,7 @@ add wave -divider add wave -hex /testbench/dut/hart/ifu/PCF add wave -hex /testbench/dut/hart/ifu/InstrF add wave /testbench/InstrFName +add wave -divider add wave -hex /testbench/dut/hart/ifu/PCD add wave -hex /testbench/dut/hart/ifu/InstrD add wave /testbench/InstrDName @@ -63,14 +64,19 @@ add wave -divider add wave -hex /testbench/dut/hart/ifu/PCE add wave -hex /testbench/dut/hart/ifu/InstrE add wave /testbench/InstrEName +add wave -divider +add wave -hex /testbench/dut/hart/ifu/PCM +add wave -hex /testbench/dut/hart/ifu/InstrM +add wave /testbench/InstrMName +add wave -divider +add wave -hex /testbench/dut/hart/ifu/PCW +add wave -hex /testbench/dut/hart/ifu/InstrW +add wave /testbench/InstrWName #add wave -hex /testbench/dut/hart/ieu/dp/SrcAE #add wave -hex /testbench/dut/hart/ieu/dp/SrcBE #add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE #add wave /testbench/dut/hart/ieu/dp/PCSrcE add wave -divider -#add wave -hex /testbench/dut/hart/ifu/PCM -#add wave -hex /testbench/dut/hart/ifu/InstrM -#add wave /testbench/InstrMName #add wave /testbench/dut/uncore/dtim/memwrite #add wave -hex /testbench/dut/uncore/HADDR #add wave -hex /testbench/dut/uncore/HWDATA @@ -84,6 +90,7 @@ add wave -divider add wave -hex -r /testbench/dut/hart/ieu/dp/regf/* add wave -divider add wave -divider +add wave -hex -r /testbench/dut/hart/ebu/ReadDataW -- Set Wave Output Items TreeUpdate [SetDefaultTree] From d3a1afe50ea8a8a1a2c16fe52ad79e524df34d89 Mon Sep 17 00:00:00 2001 From: Teo Ene Date: Wed, 3 Mar 2021 15:20:38 -0600 Subject: [PATCH 05/13] Fix to last push --- wally-pipelined/testbench/testbench-coremark.sv | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wally-pipelined/testbench/testbench-coremark.sv b/wally-pipelined/testbench/testbench-coremark.sv index 4aef5e408..9f458567a 100644 --- a/wally-pipelined/testbench/testbench-coremark.sv +++ b/wally-pipelined/testbench/testbench-coremark.sv @@ -32,7 +32,6 @@ module testbench(); logic [`XLEN-1:0] signature[0:10000]; logic [`XLEN-1:0] testadr; string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; - logic [31:0] InstrW; logic [`XLEN-1:0] meminit; string tests[]; logic [`AHBW-1:0] HRDATAEXT; @@ -62,9 +61,10 @@ module testbench(); wallypipelinedsoc dut(.*); // Track names of instructions instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE, + dut.hart.ifu.InstrF, dut.hart.ifu.InstrD, dut.hart.ifu.InstrE, - dut.hart.ifu.InstrM, InstrW, - InstrDName, InstrEName, InstrMName, InstrWName); + dut.hart.ifu.InstrM, dut.hart.ifu.InstrW, + InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // initialize tests initial begin @@ -86,13 +86,13 @@ endmodule /* verilator lint_on WIDTH */ module instrTrackerTB( input logic clk, reset, FlushE, - input logic [31:0] InstrD, + input logic [31:0] InstrF, InstrD, input logic [31:0] InstrE, InstrM, - output logic [31:0] InstrW, - output string InstrDName, InstrEName, InstrMName, InstrWName); + input logic [31:0] InstrW, + output string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // stage Instr to Writeback for visualization - flopr #(32) InstrWReg(clk, reset, InstrM, InstrW); + instrNameDecTB fdec(InstrF, InstrFName); instrNameDecTB ddec(InstrD, InstrDName); instrNameDecTB edec(InstrE, InstrEName); instrNameDecTB mdec(InstrM, InstrMName); From 5fd521d333c45432eb22f7e7d7cb2bbb4e2627ad Mon Sep 17 00:00:00 2001 From: Thomas Fleming Date: Wed, 3 Mar 2021 17:06:37 -0500 Subject: [PATCH 06/13] Create virtual memory ad-hoc test Test program is currently failing on ovpsim. There is no indication that ovpsim is properly implementing virtual memory translation when satp is set accordingly. Need to confirm whether this is a problem with ovpsim, how ovpsim is being called, or the test itself. --- .../testgen/testgen-VIRTUALMEMORY.py | 285 ++++++++++++++++++ .../testgen/virtual_memory_util.py | 125 ++++++++ 2 files changed, 410 insertions(+) create mode 100644 wally-pipelined/testgen/testgen-VIRTUALMEMORY.py create mode 100644 wally-pipelined/testgen/virtual_memory_util.py diff --git a/wally-pipelined/testgen/testgen-VIRTUALMEMORY.py b/wally-pipelined/testgen/testgen-VIRTUALMEMORY.py new file mode 100644 index 000000000..07bb6e374 --- /dev/null +++ b/wally-pipelined/testgen/testgen-VIRTUALMEMORY.py @@ -0,0 +1,285 @@ +#!/usr/bin/python3 +################################## +# testgen-VIRTUALMEMORY.py +# +# Jessica Torrey 01 March 2021 +# Thomas Fleming 01 March 2021 +# +# Generate an ad-hoc test program for RISC-V Design Validation. Tests the +# functionality of the memory management unit (MMU). +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint, seed, getrandbits +from textwrap import dedent +from virtual_memory_util import * + +################################## +# global structures +################################## + +testcase_num = 0 +signature_len = 2000 +signature = [0xff for _ in range(signature_len)] + +################################## +# functions +################################## + +def rand_reg(): + """ + Produce a random register from 1 to 31 (skipping 6, since r6 is used for + other things). + """ + r = randint(1,30) + if r >= 6: + r += 1 + return r + +def rand_regs(): + """ + Generate two random, unequal register numbers (skipping x6). + """ + rs1 = rand_reg() + rs2 = rand_reg() + while rs1 == rs2: + rs2 = rand_reg() + + return rs1, rs2 + +def initialize_page_directory() + +def generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta): + """ + Create assembly code for a given STORE test case, returned as a string. + + Generates an `xlen`-bit test case for `instruction` (one of sb, sh, sw, or + sd) that loads `value` into `value_register`, then attempts to store that + value in memory at address (x6 + `base_delta`). The test case + assumes the current base address for the signature is in register x6. + + The form of the STORE instruction is as follows: + + `instruction` `value_register` `offset`(`addr_register`) + """ + global testcase_num + + hex_value = f"{value:0{xlen // 4}x}" + + data = f"""# Testcase {testcase_num}: source: x{value_register} (value 0x{hex_value}), destination: {offset}(x{addr_register}) ({base_delta} bytes into signature) + addi x{addr_register}, x6, {base_delta} + li x{value_register}, MASK_XLEN({-offset}) + add x{addr_register}, x{addr_register}, x{value_register} + li x{value_register}, 0x{hex_value} + {instruction} x{value_register}, {offset}(x{addr_register}) + """ + + #update_signature(store_to_size[instruction], value, base_delta) + + testcase_num += 1 + return data + +def validate_memory(scratch_register, value_register, value, base_delta, length): + """ + Create assembly code to verify that `length` bytes at mem[x6 + `base_delta`] + store `value`. + + Assumes x6 stores the current base address for the signature. + """ + truncated_value = value & (2**(length * 8) - 1) + hex_value = f"{truncated_value:0{length * 2}x}" + + load = size_to_load[length] + data = f"""addi x{scratch_register}, x6, {base_delta} + {load} x{value_register}, 0(x{scratch_register}) + RVTEST_IO_ASSERT_GPR_EQ(x{scratch_register}, x{value_register}, 0x{hex_value}) + + """ + return data + +def update_signature(length, value, base_delta): + """ + Write the lower `length` bytes of `value` to the little-endian signature + array, starting at byte `base_delta`. + """ + truncated_value = value & (2**(length * 8) - 1) + value_bytes = truncated_value.to_bytes(length, 'little') + #print("n: {}, value: {:x}, trunc: {:x}, length: {}, bd: {:x}".format(testcase_num, value, truncated_value, length, base_delta)) + for i in range(length): + signature[base_delta + i] = value_bytes[i] + +def write_signature(outfile): + """ + Writes successive 32-bit words from the signature array into a given file. + """ + for i in range(0, signature_len, 4): + word = list(reversed(signature[i:i+4])) + hexword = bytearray(word).hex() + outfile.write(f"{hexword}\n") + +def write_header(outfile): + """ + Write the name of the test file, authors, and creation date. + """ + outfile.write(dedent(f"""\ + /////////////////////////////////////////// + // + // WALLY-STORE + // + // Author: {author} + // + // Created {str(datetime.now())} + """)) + outfile.write(open("testgen_header.S", "r").read()) + +def write_footer(outfile): + """ + Write necessary closing code, including a data section for the signature. + """ + outfile.write(open("testgen_footer.S", 'r').read()) + data_section = dedent(f"""\ + \t.fill {signature_len}, 1, -1 + RV_COMPLIANCE_DATA_END + """) + outfile.write(data_section) + +################################## +# test cases +################################## + +def write_basic_tests(outfile, xlen, instr_len, num, base_delta): + """ + Test basic functionality of STORE, using random registers, offsets, and + values. + + Creates `num` tests for a single store instruction of length `instr_len`, + writing to memory at consecutive locations, starting `base_delta` bytes from + the start of the signature. + + Returns the number of bytes from the start of the signature where testing + ended. + """ + instruction = size_to_store[instr_len] + for i in range(num): + value_register, addr_register = rand_regs() + offset = randint(-2**(12 - 1), 2**(12 - 1) - 1) + value = randint(0, 2**(instr_len * 8) - 1) + test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta) + validate = validate_memory(addr_register, value_register, value, base_delta, instr_len) + outfile.write(test) + outfile.write(validate) + base_delta += instr_len + return base_delta + +def write_random_store_tests(outfile, xlen, instr_len, num, min_base_delta): + """ + Test random access of STORE, using random registers, offsets, values, and + memory locations. + + Creates `num` tests for a single store instruction of length `instr_len`, + writing to memory at random locations between `min_base_delta` bytes past + the start of the signature to the end of the signature. + """ + instruction = size_to_store[instr_len] + for i in range(num): + base_delta = randint(min_base_delta, signature_len - 1) + base_delta -= (base_delta % instr_len) + value_register, addr_register = rand_regs() + offset = randint(-2**(12 - 1), 2**(12 - 1) - 1) + value = randint(0, 2**(instr_len * 8) - 1) + + test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta) + validate = validate_memory(addr_register, value_register, value, base_delta, instr_len) + outfile.write(test) + outfile.write(validate) + +def write_repeated_store_tests(outfile, xlen, instr_len, num, base_delta): + """ + Test repeated access of STORE, using random registers, offsets, values, and a + single memory location. + + Creates `num` tests for a single store instruction of length `instr_len`, + writing to memory `base_delta` bytes past the start of the signature. + """ + instruction = size_to_store[instr_len] + for i in range(num): + value_register, addr_register = rand_regs() + offset = 0 + value = (1 << ((2 * i) % xlen)) + + test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta) + validate = validate_memory(addr_register, value_register, value, base_delta, instr_len) + + outfile.write(test) + outfile.write(validate) + +def write_corner_case_tests(outfile, xlen, instr_len, base_delta): + instruction = size_to_store[instr_len] + + corner_cases_32 = [0x0, 0x10000001, 0x01111111] + corner_cases_64 = [0x1000000000000001, 0x0111111111111111] + corner_cases = corner_cases_32 + if xlen == 64: + corner_cases += corner_cases_64 + + for offset in corner_cases: + for value in corner_cases: + value_register, addr_register = rand_regs() + test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta) + validate = validate_memory(addr_register, value_register, value, base_delta, instr_len) + + outfile.write(test) + outfile.write(validate) + + base_delta += instr_len + + return base_delta + +################################## +# main body +################################## + +if __name__ == "__main__": + instructions = ["sd", "sw", "sh", "sb"] + author = "Jessica Torrey & Thomas Fleming " + xlens = [32, 64] + numrand = 100 + + # setup + seed(0) # make tests reproducible + + for xlen in xlens: + if (xlen == 32): + wordsize = 4 + else: + wordsize = 8 + + fname = f"../../imperas-riscv-tests/riscv-test-suite/rv{xlen}i/src/WALLY-VIRTUALMEMORY.S" + refname = f"../../imperas-riscv-tests/riscv-test-suite/rv{xlen}i/references/WALLY-VIRTUALMEMORY.reference_output" + f = open(fname, "w") + r = open(refname, "w") + + write_header(f) + + base_delta = 0 + + for instruction in instructions: + if xlen == 32 and instruction == 'sd': + continue + instr_len = store_to_size[instruction] + base_delta = write_basic_tests(f, xlen, instr_len, 5, base_delta) + write_repeated_store_tests(f, xlen, instr_len, 32, base_delta) + write_random_store_tests(f, xlen, instr_len, 5, base_delta + wordsize) + + write_footer(f) + + write_signature(r) + f.close() + r.close() + + # Reset testcase_num and signature + testcase_num = 0 + signature = [0xff for _ in range(signature_len)] \ No newline at end of file diff --git a/wally-pipelined/testgen/virtual_memory_util.py b/wally-pipelined/testgen/virtual_memory_util.py new file mode 100644 index 000000000..83b34d5bb --- /dev/null +++ b/wally-pipelined/testgen/virtual_memory_util.py @@ -0,0 +1,125 @@ +#!/usr/bin/python3 +################################## +# virtual_memory_util.py +# +# Jessica Torrey 01 March 2021 +# Thomas Fleming 01 March 2021 +# +# Utility functions for simulating and testing virtual memory on RISC-V. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint, seed, getrandbits +from textwrap import dedent + +################################## +# global structures +################################## +PTE_D = 1 << 7 +PTE_A = 1 << 6 +PTE_G = 1 << 5 +PTE_U = 1 << 4 +PTE_X = 1 << 3 +PTE_W = 1 << 2 +PTE_R = 1 << 1 +PTE_V = 1 << 0 + + +pgdir = [] + +testcase_num = 0 +signature_len = 2000 +signature = [0xff for _ in range(signature_len)] + +################################## +# classes +################################## +class Architecture: + def __init__(self, xlen): + if (xlen == 32): + self.PTESIZE = 4 + + self.VPN_BITS = 20 + self.VPN_SEGMENT_BITS = 10 + + self.PPN_BITS = 22 + + self.LEVELS = 2 + elif (xlen == 64): + self.PTESIZE = 8 + + self.VPN_BITS = 27 + self.VPN_SEGMENT_BITS = 9 + + self.PPN_BITS = 44 + + self.LEVELS = 3 + else: + raise ValueError('Only rv32 and rv64 are allowed.') + + self.PGSIZE = 2**12 + self.NPTENTRIES = self.PGSIZE // self.PTESIZE + self.PTE_BITS = 8 * self.PTESIZE + self.OFFSET_BITS = 12 + self.FLAG_BITS = 8 + +class PageTableEntry: + def __init__(self, ppn, flags, arch): + assert 0 <= ppn and ppn < 2**arch.PPN_BITS, "Invalid physical page number for PTE" + assert 0 <= flags and flags < 2**arch.FLAG_BITS, "Invalid flags for PTE" + self.ppn = ppn + self.flags = flags + self.arch = arch + + def entry(self): + return (self.ppn << (self.arch.PTE_BITS - self.arch.PPN_BITS)) | self.flags + + def __str__(self): + return "0x{0:0{1}x}".format(self.entry(), self.arch.PTESIZE*2) + + def __repr__(self): + return f"" + +class PageTable: + """ + Represents a single level of the page table, with + """ + def __init__(self, name, arch): + self.table = {} + self.name = name + self.arch = arch + + def add_entry(self, vpn_segment, ppn_segment, flags, linked_table = None): + if not (0 <= vpn_segment < 2**self.arch.VPN_SEGMENT_BITS): + raise ValueError("Invalid virtual page segment number") + self.table[vpn_segment] = (PageTableEntry(ppn_segment, flags, self.arch), linked_table) + + def add_mapping(self, va, pa, flags): + if not (0 <= va < 2**self.arch.VPN_BITS): + raise ValueError("Invalid virtual page number") + for level in range(self.arch.LEVELS - 1, -1, -1): + + + + + def assembly(self): + entries = list(sorted(self.table.items(), key=lambda item: item[0])) + current_index = 0 + asm = f".balign {self.arch.PGSIZE}\n{self.name}:\n" + for entry in entries: + vpn_index, (pte, _) = entry + if current_index < vpn_index: + asm += f" .fill {vpn_index - current_index}, {self.arch.PTESIZE}, 0\n" + asm += f" .4byte {str(pte)}\n" + current_index = vpn_index + 1 + if current_index < self.arch.NPTENTRIES: + asm += f" .fill {self.arch.NPTENTRIES - current_index}, {self.arch.PTESIZE}, 0\n" + return asm + +################################## +# functions +################################## + From c03b540956f14152cc570c4e42a0ca516bf9781d Mon Sep 17 00:00:00 2001 From: Thomas Fleming Date: Thu, 4 Mar 2021 01:13:31 -0500 Subject: [PATCH 07/13] Generalize tlb module - number of tlb entries is now parameterized - tlb now supports rv64i --- wally-pipelined/src/tlb_toy/tlb_testbench.sv | 23 +-- wally-pipelined/src/tlb_toy/tlb_toy.sv | 179 +++++++++++-------- 2 files changed, 115 insertions(+), 87 deletions(-) diff --git a/wally-pipelined/src/tlb_toy/tlb_testbench.sv b/wally-pipelined/src/tlb_toy/tlb_testbench.sv index add65d3db..4e2c71997 100644 --- a/wally-pipelined/src/tlb_toy/tlb_testbench.sv +++ b/wally-pipelined/src/tlb_toy/tlb_testbench.sv @@ -2,19 +2,22 @@ module testbench(); logic clk, reset; // DUT inputs - logic [31:0] PCF; - logic [31:0] PageTableEntryF; - logic ITLBWriteF, ITLBFlushF; + logic [`XLEN-1:0] SATP; + logic [`XLEN-1:0] VirtualAddress; + logic [`XLEN-1:0] PageTableEntryWrite; + logic TLBWrite, TLBFlush; // DUT outputs - logic [31:0] PCPF; - logic ITLBMissF, ITLBHitF; + logic [`XLEN-1:0] PhysicalAddress; + logic TLBMiss, TLBHit; // Testbench signals logic [33:0] expected; logic [31:0] vectornum, errors; logic [99:0] testvectors[10000:0]; + assign SATP = {1'b1, 31'b0}; + // instantiate device under test tlb_toy dut(.*); @@ -31,17 +34,17 @@ module testbench(); // apply test vectors on rising edge of clk always @(posedge clk) begin - #1; {PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF, expected} = testvectors[vectornum]; + #1; {VirtualAddress, PageTableEntryWrite, TLBWrite, TLBFlush, expected} = testvectors[vectornum]; end // check results on falling edge of clk always @(negedge clk) if (~reset) begin // skip during reset - if ({PCPF, ITLBMissF, ITLBHitF} !== expected) begin // check result - $display("Error: PCF = %b, write = %b, data = %b, flush = %b", PCF, - ITLBWriteF, PageTableEntryF, ITLBFlushF); + if ({PhysicalAddress, TLBMiss, TLBHit} !== expected) begin // check result + $display("Error: VirtualAddress = %b, write = %b, data = %b, flush = %b", VirtualAddress, + TLBWrite, PageTableEntryWrite, TLBFlush); $display(" outputs = %b %b %b (%b expected)", - PCPF, ITLBMissF, ITLBHitF, expected); + PhysicalAddress, TLBMiss, TLBHit, expected); errors = errors + 1; end vectornum = vectornum + 1; diff --git a/wally-pipelined/src/tlb_toy/tlb_toy.sv b/wally-pipelined/src/tlb_toy/tlb_toy.sv index 43c94babe..cafc15faf 100644 --- a/wally-pipelined/src/tlb_toy/tlb_toy.sv +++ b/wally-pipelined/src/tlb_toy/tlb_toy.sv @@ -24,7 +24,7 @@ // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////// -// `include "wally-config.vh" +`include "wally-config.vh" /** * sv32 specs @@ -49,126 +49,159 @@ /* *** TODO: * - add LRU algorithm (select the write index based on which entry was used * least recently) - * - rename signals to use .* notation in CAM and RAM */ -module tlb_toy ( - input clk, reset, +// The TLB will have 2**ENTRY_BITS total entries +module tlb_toy #(parameter ENTRY_BITS = 3) ( + input clk, reset, + + // Current value of satp CSR (from privileged unit) + input [`XLEN-1:0] SATP, // *** How do we get this? // Virtual address input - input [31:0] PCF, + input [`XLEN-1:0] VirtualAddress, // Controls for writing a new entry to the TLB - input [31:0] PageTableEntryF, - input ITLBWriteF, + input [`XLEN-1:0] PageTableEntryWrite, + input TLBWrite, // Invalidate all TLB entries - input ITLBFlushF, + input TLBFlush, // Physical address outputs - output [31:0] PCPF, - output ITLBMissF, - output ITLBHitF + output [`XLEN-1:0] PhysicalAddress, + output TLBMiss, + output TLBHit ); + + generate + if (`XLEN == 32) begin: ARCH + localparam VPN_BITS = 20; + localparam PPN_BITS = 22; + localparam PA_BITS = 34; + + logic SvMode; + assign SvMode = SATP[31]; // *** change to an enum somehow? + end else begin: ARCH + localparam VPN_BITS = 27; + localparam PPN_BITS = 44; + localparam PA_BITS = 56; + + logic SvMode; // currently just a boolean whether translation enabled + assign SvMode = SATP[63]; // *** change to an enum somehow? + end + endgenerate + // Index (currently random) to write the next TLB entry - logic [2:0] WriteIndexF; + logic [ENTRY_BITS-1:0] WriteIndex; // Sections of the virtual and physical addresses - logic [19:0] VirtualPageNumberF; - logic [21:0] PhysicalPageNumberF; - logic [11:0] PageOffsetF; - logic [33:0] PhysicalAddressF; + logic [ARCH.VPN_BITS-1:0] VirtualPageNumber; + logic [ARCH.PPN_BITS-1:0] PhysicalPageNumber; + logic [11:0] PageOffset; + logic [ARCH.PA_BITS-1:0] PhysicalAddressFull; // Pattern and pattern location in the CAM - logic [2:0] VPNIndexF; + logic [ENTRY_BITS-1:0] VPNIndex; // RAM access location - logic [2:0] ITLBEntryIndex; + logic [ENTRY_BITS-1:0] EntryIndex; // Page table entry matching the virtual address - logic [31:0] PTEMatchF; + logic [`XLEN-1:0] PageTableEntry; - assign VirtualPageNumberF = PCF[31:12]; - assign PageOffsetF = PCF[11:0]; + assign VirtualPageNumber = VirtualAddress[ARCH.VPN_BITS+11:12]; + assign PageOffset = VirtualAddress[11:0]; // Choose a read or write location to the entry list - mux2 #(3) indexmux(VPNIndexF, WriteIndexF, ITLBWriteF, ITLBEntryIndex); + mux2 #(3) indexmux(VPNIndex, WriteIndex, TLBWrite, EntryIndex); // Currently use random replacement algorithm - rand3 rdm(clk, reset, WriteIndexF); + tlb_rand rdm(.*); - ram8x32 ram(clk, reset, ITLBEntryIndex, PageTableEntryF, ITLBWriteF, PTEMatchF); - cam8x21 cam(clk, reset, ITLBWriteF, VirtualPageNumberF, WriteIndexF, - ITLBFlushF, VPNIndexF, ITLBHitF); + tlb_ram #(ENTRY_BITS) ram(.*); + tlb_cam #(ENTRY_BITS, ARCH.VPN_BITS) cam(.*); always_comb begin - assign PhysicalPageNumberF = PTEMatchF[31:10]; + assign PhysicalPageNumber = PageTableEntry[ARCH.PPN_BITS+9:10]; - if (ITLBHitF) begin - assign PhysicalAddressF = {PhysicalPageNumberF, PageOffsetF}; + if (TLBHit) begin + assign PhysicalAddressFull = {PhysicalPageNumber, PageOffset}; end else begin - assign PhysicalAddressF = 34'b0; + assign PhysicalAddressFull = 8'b0; // *** Actual behavior; disabled until walker functioning + //assign PhysicalAddressFull = {2'b0, VirtualPageNumber, PageOffset} // *** pass through should be removed as soon as walker ready end end - assign PCPF = PhysicalAddressF[31:0]; - assign ITLBMissF = ~ITLBHitF & ~(ITLBWriteF | ITLBFlushF); + generate + if (`XLEN == 32) begin + mux2 #(`XLEN) addressmux(VirtualAddress, PhysicalAddressFull[31:0], ARCH.SvMode, PhysicalAddress); + end else begin + mux2 #(`XLEN) addressmux(VirtualAddress, {8'b0, PhysicalAddressFull}, ARCH.SvMode, PhysicalAddress); + end + endgenerate + assign TLBMiss = ~TLBHit & ~(TLBWrite | TLBFlush) & ARCH.SvMode; endmodule -// *** Add parameter for number of tlb lines (currently 8) -module ram8x32 ( - input clk, reset, - input [2:0] address, - input [31:0] data, - input we, +module tlb_ram #(parameter ENTRY_BITS = 3) ( + input clk, reset, + input [ENTRY_BITS-1:0] EntryIndex, + input [`XLEN-1:0] PageTableEntryWrite, + input TLBWrite, - output [31:0] out_data + output [`XLEN-1:0] PageTableEntry ); - logic [31:0] ram [0:7]; + localparam NENTRIES = 2**ENTRY_BITS; + + logic [`XLEN-1:0] ram [0:NENTRIES-1]; always @(posedge clk) begin - if (we) ram[address] <= data; + if (TLBWrite) ram[EntryIndex] <= PageTableEntryWrite; end - assign out_data = ram[address]; + assign PageTableEntry = ram[EntryIndex]; initial begin - for (int i = 0; i < 8; i++) - ram[i] = 32'h0; + for (int i = 0; i < NENTRIES; i++) + ram[i] = `XLEN'b0; end endmodule -module cam8x21 ( - input clk, reset, we, - input [19:0] pattern, - input [2:0] write_address, - input ITLBFlushF, - output [2:0] matched_address, - output match_found +module tlb_cam #(parameter ENTRY_BITS = 3, + parameter KEY_BITS = 20) ( + input clk, reset, + input [KEY_BITS-1:0] VirtualPageNumber, + input [ENTRY_BITS-1:0] WriteIndex, + input TLBWrite, + input TLBFlush, + output [ENTRY_BITS-1:0] VPNIndex, + output TLBHit ); - logic [20:0] ram [0:7]; - logic [7:0] match_line; + localparam NENTRIES = 2**ENTRY_BITS; - logic [2:0] matched_address_comb; - logic match_found_comb; + // Each entry of this memory has KEY_BITS for the key plus one valid bit. + logic [KEY_BITS:0] ram [0:NENTRIES-1]; + + logic [ENTRY_BITS-1:0] matched_address_comb; + logic match_found_comb; always @(posedge clk) begin - if (we) ram[write_address] <= {1'b1,pattern}; - if (ITLBFlushF) begin - for (int i = 0; i < 8; i++) - ram[i][20] = 1'b0; + if (TLBWrite) ram[WriteIndex] <= {1'b1,VirtualPageNumber}; + if (TLBFlush) begin + for (int i = 0; i < NENTRIES; i++) + ram[i][KEY_BITS] = 1'b0; // Zero out msb (valid bit) of all entries end end // *** Check whether this for loop synthesizes correctly always_comb begin match_found_comb = 1'b0; - matched_address_comb = 3'b0; - for (int i = 0; i < 8; i++) begin - if (ram[i] == {1'b1,pattern} && !match_found_comb) begin + matched_address_comb = '0; + for (int i = 0; i < NENTRIES; i++) begin + if (ram[i] == {1'b1,VirtualPageNumber} && !match_found_comb) begin matched_address_comb = i; match_found_comb = 1; end else begin @@ -178,31 +211,23 @@ module cam8x21 ( end end - assign matched_address = matched_address_comb; - assign match_found = match_found_comb & ~(we | ITLBFlushF); + assign VPNIndex = matched_address_comb; + assign TLBHit = match_found_comb & ~(TLBWrite | TLBFlush); initial begin - for (int i = 0; i < 8; i++) - ram[i] <= 0; + for (int i = 0; i < NENTRIES; i++) + ram[i] <= '0; end endmodule -module mux2 #(parameter WIDTH = 8) ( - input logic [WIDTH-1:0] d0, d1, - input logic s, - output logic [WIDTH-1:0] y); - - assign y = s ? d1 : d0; -endmodule - -module rand3 ( +module tlb_rand #(parameter ENTRY_BITS = 3) ( input clk, reset, - output [2:0] WriteIndexF + output [ENTRY_BITS:0] WriteIndex ); logic [31:0] data; assign data = $urandom; - assign WriteIndexF = data[2:0]; + assign WriteIndex = data[ENTRY_BITS:0]; endmodule From b15ef47d246726bce99a78123b297912297dbf7f Mon Sep 17 00:00:00 2001 From: Teo Ene Date: Thu, 4 Mar 2021 01:33:34 -0600 Subject: [PATCH 08/13] Fix to 32-bit option of commit 2d408981587280bbcd075c281794d74c0cfa3aa7 --- wally-pipelined/src/uncore/imem.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wally-pipelined/src/uncore/imem.sv b/wally-pipelined/src/uncore/imem.sv index 9aa37e49e..68ef87519 100644 --- a/wally-pipelined/src/uncore/imem.sv +++ b/wally-pipelined/src/uncore/imem.sv @@ -53,7 +53,7 @@ module imem ( generate if (`XLEN==32) begin assign InstrF = AdrF[1] ? {rd2[15:0], rd[31:16]} : rd; - assign InstrAccessFaultF = ~&(({AdrF,0} ~^ `TIMBASE) | `TIMRANGE); + assign InstrAccessFaultF = ~&(({AdrF,1'b0} ~^ `TIMBASE) | `TIMRANGE); end else begin assign InstrF = AdrF[2] ? (AdrF[1] ? {rd2[15:0], rd[63:48]} : rd[63:32]) : (AdrF[1] ? rd[47:16] : rd[31:0]); From 7a9f866120dccd3e3c65278a0f571e4c3dbf1de8 Mon Sep 17 00:00:00 2001 From: Thomas Fleming Date: Thu, 4 Mar 2021 02:39:08 -0500 Subject: [PATCH 09/13] Move tlb into mmu directory --- wally-pipelined/src/mmu/tlb.sv | 233 +++++++++++++++++++ wally-pipelined/src/tlb_toy/tlb_testbench.sv | 4 +- 2 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 wally-pipelined/src/mmu/tlb.sv diff --git a/wally-pipelined/src/mmu/tlb.sv b/wally-pipelined/src/mmu/tlb.sv new file mode 100644 index 000000000..cafc15faf --- /dev/null +++ b/wally-pipelined/src/mmu/tlb.sv @@ -0,0 +1,233 @@ +/////////////////////////////////////////// +// tlb_toy.sv +// +// Written: jtorrey@hmc.edu 16 February 2021 +// Modified: +// +// Purpose: Example translation lookaside buffer +// Cache of virtural-to-physical address translations +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +`include "wally-config.vh" + +/** + * sv32 specs + * ---------- + * Virtual address [31:0] (32 bits) + * [________________________________] + * |--VPN1--||--VPN0--||----OFF---| + * 10 10 12 + * + * Physical address [33:0] (34 bits) + * [__________________________________] + * |---PPN1---||--PPN0--||----OFF---| + * 12 10 12 + * + * Page Table Entry [31:0] (32 bits) + * [________________________________] + * |---PPN1---||--PPN0--|||DAGUXWRV + * 12 10 ^^ + * RSW(2) -- for OS + */ + +/* *** TODO: + * - add LRU algorithm (select the write index based on which entry was used + * least recently) + */ + +// The TLB will have 2**ENTRY_BITS total entries +module tlb_toy #(parameter ENTRY_BITS = 3) ( + input clk, reset, + + // Current value of satp CSR (from privileged unit) + input [`XLEN-1:0] SATP, // *** How do we get this? + + // Virtual address input + input [`XLEN-1:0] VirtualAddress, + + // Controls for writing a new entry to the TLB + input [`XLEN-1:0] PageTableEntryWrite, + input TLBWrite, + + // Invalidate all TLB entries + input TLBFlush, + + // Physical address outputs + output [`XLEN-1:0] PhysicalAddress, + output TLBMiss, + output TLBHit +); + + generate + if (`XLEN == 32) begin: ARCH + localparam VPN_BITS = 20; + localparam PPN_BITS = 22; + localparam PA_BITS = 34; + + logic SvMode; + assign SvMode = SATP[31]; // *** change to an enum somehow? + end else begin: ARCH + localparam VPN_BITS = 27; + localparam PPN_BITS = 44; + localparam PA_BITS = 56; + + logic SvMode; // currently just a boolean whether translation enabled + assign SvMode = SATP[63]; // *** change to an enum somehow? + end + endgenerate + + // Index (currently random) to write the next TLB entry + logic [ENTRY_BITS-1:0] WriteIndex; + + // Sections of the virtual and physical addresses + logic [ARCH.VPN_BITS-1:0] VirtualPageNumber; + logic [ARCH.PPN_BITS-1:0] PhysicalPageNumber; + logic [11:0] PageOffset; + logic [ARCH.PA_BITS-1:0] PhysicalAddressFull; + + // Pattern and pattern location in the CAM + logic [ENTRY_BITS-1:0] VPNIndex; + + // RAM access location + logic [ENTRY_BITS-1:0] EntryIndex; + + // Page table entry matching the virtual address + logic [`XLEN-1:0] PageTableEntry; + + assign VirtualPageNumber = VirtualAddress[ARCH.VPN_BITS+11:12]; + assign PageOffset = VirtualAddress[11:0]; + + // Choose a read or write location to the entry list + mux2 #(3) indexmux(VPNIndex, WriteIndex, TLBWrite, EntryIndex); + + // Currently use random replacement algorithm + tlb_rand rdm(.*); + + tlb_ram #(ENTRY_BITS) ram(.*); + tlb_cam #(ENTRY_BITS, ARCH.VPN_BITS) cam(.*); + + always_comb begin + assign PhysicalPageNumber = PageTableEntry[ARCH.PPN_BITS+9:10]; + + if (TLBHit) begin + assign PhysicalAddressFull = {PhysicalPageNumber, PageOffset}; + end else begin + assign PhysicalAddressFull = 8'b0; // *** Actual behavior; disabled until walker functioning + //assign PhysicalAddressFull = {2'b0, VirtualPageNumber, PageOffset} // *** pass through should be removed as soon as walker ready + end + end + + generate + if (`XLEN == 32) begin + mux2 #(`XLEN) addressmux(VirtualAddress, PhysicalAddressFull[31:0], ARCH.SvMode, PhysicalAddress); + end else begin + mux2 #(`XLEN) addressmux(VirtualAddress, {8'b0, PhysicalAddressFull}, ARCH.SvMode, PhysicalAddress); + end + endgenerate + + assign TLBMiss = ~TLBHit & ~(TLBWrite | TLBFlush) & ARCH.SvMode; +endmodule + +module tlb_ram #(parameter ENTRY_BITS = 3) ( + input clk, reset, + input [ENTRY_BITS-1:0] EntryIndex, + input [`XLEN-1:0] PageTableEntryWrite, + input TLBWrite, + + output [`XLEN-1:0] PageTableEntry +); + + localparam NENTRIES = 2**ENTRY_BITS; + + logic [`XLEN-1:0] ram [0:NENTRIES-1]; + always @(posedge clk) begin + if (TLBWrite) ram[EntryIndex] <= PageTableEntryWrite; + end + + assign PageTableEntry = ram[EntryIndex]; + + initial begin + for (int i = 0; i < NENTRIES; i++) + ram[i] = `XLEN'b0; + end + +endmodule + +module tlb_cam #(parameter ENTRY_BITS = 3, + parameter KEY_BITS = 20) ( + input clk, reset, + input [KEY_BITS-1:0] VirtualPageNumber, + input [ENTRY_BITS-1:0] WriteIndex, + input TLBWrite, + input TLBFlush, + output [ENTRY_BITS-1:0] VPNIndex, + output TLBHit +); + + localparam NENTRIES = 2**ENTRY_BITS; + + // Each entry of this memory has KEY_BITS for the key plus one valid bit. + logic [KEY_BITS:0] ram [0:NENTRIES-1]; + + logic [ENTRY_BITS-1:0] matched_address_comb; + logic match_found_comb; + + always @(posedge clk) begin + if (TLBWrite) ram[WriteIndex] <= {1'b1,VirtualPageNumber}; + if (TLBFlush) begin + for (int i = 0; i < NENTRIES; i++) + ram[i][KEY_BITS] = 1'b0; // Zero out msb (valid bit) of all entries + end + end + + // *** Check whether this for loop synthesizes correctly + always_comb begin + match_found_comb = 1'b0; + matched_address_comb = '0; + for (int i = 0; i < NENTRIES; i++) begin + if (ram[i] == {1'b1,VirtualPageNumber} && !match_found_comb) begin + matched_address_comb = i; + match_found_comb = 1; + end else begin + matched_address_comb = matched_address_comb; + match_found_comb = match_found_comb; + end + end + end + + assign VPNIndex = matched_address_comb; + assign TLBHit = match_found_comb & ~(TLBWrite | TLBFlush); + + initial begin + for (int i = 0; i < NENTRIES; i++) + ram[i] <= '0; + end + +endmodule + +module tlb_rand #(parameter ENTRY_BITS = 3) ( + input clk, reset, + output [ENTRY_BITS:0] WriteIndex +); + + logic [31:0] data; + assign data = $urandom; + assign WriteIndex = data[ENTRY_BITS:0]; + +endmodule diff --git a/wally-pipelined/src/tlb_toy/tlb_testbench.sv b/wally-pipelined/src/tlb_toy/tlb_testbench.sv index 4e2c71997..4aa30542e 100644 --- a/wally-pipelined/src/tlb_toy/tlb_testbench.sv +++ b/wally-pipelined/src/tlb_toy/tlb_testbench.sv @@ -1,4 +1,6 @@ -module testbench(); +`include "wally-config.vh" + +module tlb_testbench(); logic clk, reset; // DUT inputs From 1a2db17ee5a5917d327733a39c0b116763b43e35 Mon Sep 17 00:00:00 2001 From: Thomas Fleming Date: Thu, 4 Mar 2021 03:11:34 -0500 Subject: [PATCH 10/13] Install tlb into ifu --- wally-pipelined/src/ifu/ifu.sv | 18 +++++++++++++++++- wally-pipelined/src/mmu/tlb.sv | 5 +++-- .../src/tlb_toy/{tlb_toy.sv => tlb_toy.sv.OLD} | 0 .../src/wally/wallypipelinedhart.sv | 3 +++ 4 files changed, 23 insertions(+), 3 deletions(-) rename wally-pipelined/src/tlb_toy/{tlb_toy.sv => tlb_toy.sv.OLD} (100%) diff --git a/wally-pipelined/src/ifu/ifu.sv b/wally-pipelined/src/ifu/ifu.sv index 1cddbe6dd..f5225d677 100644 --- a/wally-pipelined/src/ifu/ifu.sv +++ b/wally-pipelined/src/ifu/ifu.sv @@ -52,6 +52,12 @@ module ifu ( output logic IllegalIEUInstrFaultD, output logic InstrMisalignedFaultM, output logic [`XLEN-1:0] InstrMisalignedAdrM, + // TLB Management + //input logic [`XLEN-1:0] PageTableEntryF, + //input logic ITLBWriteF, ITLBFlushF, + // *** satp value will come from CSRs + // input logic [`XLEN-1:0] SATP, + output logic ITLBMissF, ITLBHitF, // bogus input logic [15:0] rd2 ); @@ -65,8 +71,18 @@ module ifu ( logic [31:0] InstrF, InstrRawD, InstrE, InstrW; logic [31:0] nop = 32'h00000013; // instruction for NOP + // *** temporary hack until we can figure out how to get actual satp value + // from priv unit -- Thomas F + logic [`XLEN-1:0] SATP = '0; + // *** temporary hack until walker is hooked up -- Thomas F + logic [`XLEN-1:0] PageTableEntryF = '0; + logic ITLBFlushF = '0; + logic ITLBWriteF = '0; + tlb #(3) itlb(clk, reset, SATP, PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF, + InstrPAdrF, ITLBMissF, ITLBHitF); + // *** put memory interface on here, InstrF becomes output - assign InstrPAdrF = PCF; // *** no MMU + //assign InstrPAdrF = PCF; // *** no MMU //assign InstrReadF = ~StallD; // *** & ICacheMissF; add later assign InstrReadF = 1; // *** & ICacheMissF; add later diff --git a/wally-pipelined/src/mmu/tlb.sv b/wally-pipelined/src/mmu/tlb.sv index cafc15faf..7be0f0b75 100644 --- a/wally-pipelined/src/mmu/tlb.sv +++ b/wally-pipelined/src/mmu/tlb.sv @@ -49,10 +49,11 @@ /* *** TODO: * - add LRU algorithm (select the write index based on which entry was used * least recently) + * - refactor modules into multiple files */ // The TLB will have 2**ENTRY_BITS total entries -module tlb_toy #(parameter ENTRY_BITS = 3) ( +module tlb #(parameter ENTRY_BITS = 3) ( input clk, reset, // Current value of satp CSR (from privileged unit) @@ -223,7 +224,7 @@ endmodule module tlb_rand #(parameter ENTRY_BITS = 3) ( input clk, reset, - output [ENTRY_BITS:0] WriteIndex + output [ENTRY_BITS-1:0] WriteIndex ); logic [31:0] data; diff --git a/wally-pipelined/src/tlb_toy/tlb_toy.sv b/wally-pipelined/src/tlb_toy/tlb_toy.sv.OLD similarity index 100% rename from wally-pipelined/src/tlb_toy/tlb_toy.sv rename to wally-pipelined/src/tlb_toy/tlb_toy.sv.OLD diff --git a/wally-pipelined/src/wally/wallypipelinedhart.sv b/wally-pipelined/src/wally/wallypipelinedhart.sv index 1628809db..139a276ec 100644 --- a/wally-pipelined/src/wally/wallypipelinedhart.sv +++ b/wally-pipelined/src/wally/wallypipelinedhart.sv @@ -87,6 +87,9 @@ module wallypipelinedhart ( logic FloatRegWriteW; logic SquashSCW; + // memory management unit signals + logic ITLBMissF, ITLBHitF; + // bus interface to dmem logic MemReadM, MemWriteM; logic [2:0] Funct3M; From 8c410b6fbe038ff2cccd01927388e4f2067c0ca3 Mon Sep 17 00:00:00 2001 From: Thomas Fleming Date: Thu, 4 Mar 2021 03:30:06 -0500 Subject: [PATCH 11/13] Install dtlb in dmem --- wally-pipelined/src/dmem/dmem.sv | 19 +++++++++++++++++-- wally-pipelined/src/ifu/ifu.sv | 2 +- .../src/wally/wallypipelinedhart.sv | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/wally-pipelined/src/dmem/dmem.sv b/wally-pipelined/src/dmem/dmem.sv index 588739320..aa4327c21 100644 --- a/wally-pipelined/src/dmem/dmem.sv +++ b/wally-pipelined/src/dmem/dmem.sv @@ -48,13 +48,28 @@ module dmem ( // faults input logic DataAccessFaultM, output logic LoadMisalignedFaultM, LoadAccessFaultM, - output logic StoreMisalignedFaultM, StoreAccessFaultM + output logic StoreMisalignedFaultM, StoreAccessFaultM, + // TLB management + //input logic [`XLEN-1:0] PageTableEntryM, + //input logic DTLBWriteM, DTLBFlushM, + // *** satp value will come from CSRs + // input logic [`XLEN-1:0] SATP, + output logic DTLBMissM, DTLBHitM ); logic SquashSCM; // Initially no MMU - assign MemPAdrM = MemAdrM; + // *** temporary hack until we can figure out how to get actual satp value + // from priv unit -- Thomas F + logic [`XLEN-1:0] SATP = '0; + // *** temporary hack until walker is hooked up -- Thomas F + logic [`XLEN-1:0] PageTableEntryM = '0; + logic DTLBFlushM = '0; + logic DTLBWriteM = '0; + tlb #(3) dtlb(clk, reset, SATP, MemAdrM, PageTableEntryM, DTLBWriteM, + DTLBFlushM, MemPAdrM, DTLBMissM, DTLBHitM); + //assign MemPAdrM = MemAdrM; // Determine if an Unaligned access is taking place always_comb diff --git a/wally-pipelined/src/ifu/ifu.sv b/wally-pipelined/src/ifu/ifu.sv index f5225d677..88e4f0bef 100644 --- a/wally-pipelined/src/ifu/ifu.sv +++ b/wally-pipelined/src/ifu/ifu.sv @@ -52,7 +52,7 @@ module ifu ( output logic IllegalIEUInstrFaultD, output logic InstrMisalignedFaultM, output logic [`XLEN-1:0] InstrMisalignedAdrM, - // TLB Management + // TLB management //input logic [`XLEN-1:0] PageTableEntryF, //input logic ITLBWriteF, ITLBFlushF, // *** satp value will come from CSRs diff --git a/wally-pipelined/src/wally/wallypipelinedhart.sv b/wally-pipelined/src/wally/wallypipelinedhart.sv index 139a276ec..ded4df3d8 100644 --- a/wally-pipelined/src/wally/wallypipelinedhart.sv +++ b/wally-pipelined/src/wally/wallypipelinedhart.sv @@ -89,6 +89,7 @@ module wallypipelinedhart ( // memory management unit signals logic ITLBMissF, ITLBHitF; + logic DTLBMissM, DTLBHitM; // bus interface to dmem logic MemReadM, MemWriteM; From 7852d866ef1d79b1b274259995c1f520c2b82a20 Mon Sep 17 00:00:00 2001 From: bbracker Date: Thu, 4 Mar 2021 10:37:30 -0500 Subject: [PATCH 13/13] JALR testing --- .../testbench/testbench-imperas.sv | 2 + .../{testgen-JAL.py => testgen-JAL-JALR.py} | 232 ++++++++++-------- 2 files changed, 131 insertions(+), 103 deletions(-) rename wally-pipelined/testgen/{testgen-JAL.py => testgen-JAL-JALR.py} (53%) diff --git a/wally-pipelined/testbench/testbench-imperas.sv b/wally-pipelined/testbench/testbench-imperas.sv index e810eae83..49a5263d6 100644 --- a/wally-pipelined/testbench/testbench-imperas.sv +++ b/wally-pipelined/testbench/testbench-imperas.sv @@ -162,6 +162,7 @@ string tests64iNOc[] = { "rv64i/WALLY-SRAI", "3000", "rv64i/WALLY-LOAD", "11bf0", "rv64i/WALLY-JAL", "4000", + "rv64i/WALLY-JALR", "3000", "rv64i/WALLY-STORE", "3000", "rv64i/WALLY-ADDIW", "3000", "rv64i/WALLY-SLLIW", "3000", @@ -288,6 +289,7 @@ string tests32i[] = { "rv32i/WALLY-SUB", "3000", "rv32i/WALLY-STORE", "2000", "rv32i/WALLY-JAL", "3000", + "rv32i/WALLY-JALR", "2000", "rv32i/WALLY-BEQ" ,"4000", "rv32i/WALLY-BNE", "4000 ", "rv32i/WALLY-BLTU", "4000 ", diff --git a/wally-pipelined/testgen/testgen-JAL.py b/wally-pipelined/testgen/testgen-JAL-JALR.py similarity index 53% rename from wally-pipelined/testgen/testgen-JAL.py rename to wally-pipelined/testgen/testgen-JAL-JALR.py index 09f58a566..87c0c423d 100755 --- a/wally-pipelined/testgen/testgen-JAL.py +++ b/wally-pipelined/testgen/testgen-JAL-JALR.py @@ -19,9 +19,8 @@ from random import getrandbits from copy import deepcopy ################################## -# functions +# helper functions ################################## - def InitTestGroup(): global TestGroup,TestGroupSizes,AllRegs,UnusedRegs,StoreAdrReg TestGroup += 1 @@ -44,19 +43,21 @@ def registerSelect(): if len(UnusedRegs)==0: InitTestGroup() rd = choice(UnusedRegs) - rs = choice(UnusedRegs) UnusedRegs.remove(rd) + OtherRegs = deepcopy(UnusedRegs) + if 0 in OtherRegs: + OtherRegs.remove(0) + if len(OtherRegs) == 0: + OtherRegs = deepcopy(AllRegs) + OtherRegs.remove(0) + rs = choice(OtherRegs) OtherRegs = deepcopy(AllRegs) OtherRegs.remove(StoreAdrReg) OtherRegs.remove(rd) - try: + if 0 in OtherRegs: OtherRegs.remove(0) - except: - pass - try: + if rs in OtherRegs: OtherRegs.remove(rs) - except: - pass DataReg = choice(OtherRegs) OtherRegs.remove(DataReg) OtherRd = choice(OtherRegs) @@ -65,52 +66,74 @@ def registerSelect(): def addInst(line): global CurrAdr f.write(line) - if ("li x" in line): + if ("li x" in line) and ("slli x" not in line): CurrAdr += 8 if (xlen == 32) else 20 elif ("la x" in line): CurrAdr += 8 else: CurrAdr += 4 -def writeForwardsJumpVector(spacers): - global TestNum - rd, rs, DataReg, OtherRd = registerSelect() - if (xlen==64): - expected = int("fedbca9876540000",16) - unexpected = int("ffff0000ffff0000",16) +def expectValue(expectReg, expectVal, sigOffset): + global TestGroupSizes + TestGroupSizes[TestGroup-1] += 1 + addInst(" "+storecmd+" x"+str(expectReg)+", "+str(wordsize*sigOffset)+"(x"+str(StoreAdrReg)+")\n") + f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(expectReg)+", "+formatstr.format(expectVal)+")\n") + if (xlen == 32): + r.write(formatrefstr.format(expectVal)+"\n") else: - expected = int("fedbca98",16) - unexpected = int("ff00ff00",16) + r.write(formatrefstr.format(expectVal % 2**32)+"\n" + formatrefstr.format(expectVal >> 32)+"\n") +def addJalr(rs,rd,dist): + target = CurrAdr + 20 + dist + target31_12 = CurrAdr >> 12 # 20 bits for lui + target11_0 = target - (target31_12 << 12) # 12 remaining bits + target31_16 = target31_12 >> 4 # lui sign extends, so shift in a leading 0 + target15_12 = target31_12 - (target31_16 << 4) # the nibble we just lost + if target11_0 > 0: + offset = randint(-(1<<11)-1,(1<<11)-2-target11_0) + else: + offset = randint(-(1<<11)-1-target11_0,(1<<11)-2) + addInst(" lui x"+str(rs)+", 0x"+imm20formatstr.format(target31_16)+"\n") + addInst(" addi x"+str(rs)+", x"+str(rs)+", SEXT_IMM(0x0"+imm12formatstr.format(target15_12 << 8)+")\n") + addInst(" slli x"+str(rs)+", x"+str(rs)+", SEXT_IMM(4)\n") + addInst(" addi x"+str(rs)+", x"+str(rs)+", SEXT_IMM(0x"+imm12formatstr.format(0xfff&(offset+target11_0+randint(0,1)))+")\n") + addInst(" JALR x"+str(rd)+", x"+str(rs)+", SEXT_IMM(0x"+imm12formatstr.format(0xfff&(-offset))+")\n") +################################## +# test functions +################################## +def writeForwardsJumpVector(spacers,instr): + global TestNum + TestNum += 1 + rd, rs, DataReg, OtherRd = registerSelect() + # Header f.write("\n") - f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"("+formatstr.format(CurrAdr+44)+") data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n") + f.write(" # Testcase "+str(TestNum)+"\n") + # Test Code addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n") - addInst(" JAL x"+str(rd)+", 1f\n") + if (instr=="JAL"): + addInst(" JAL x"+str(rd)+", 1f\n") + elif (instr=="JALR"): + dist = spacers*(8 if (xlen == 32) else 20) # Compute distance from linked adr to target adr + addJalr(rs,rd,dist); + else: + exit("invalid instruction") LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value for i in range(spacers): addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n") f.write("1:\n") - addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n") - f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n") - addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n") - f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n") - writeExpectedToRef(LinkAdr) - writeExpectedToRef(expected) - TestNum = TestNum+1 + # Store values to be verified + expectValue(rd, LinkAdr, 2*TestNum+0) + expectValue(DataReg, expected, 2*TestNum+1) -def writeBackwardsJumpVector(spacers): +def writeBackwardsJumpVector(spacers,instr): global TestNum - rd, rs, DataReg,OtherRd = registerSelect() - if (xlen==64): - expected = int("fedbca9876540000",16) - unexpected = int("ffff0000ffff0000",16) - else: - expected = int("fedbca98",16) - unexpected = int("ff00ff00",16) - + TestNum += 1 + rd, rs, DataReg, OtherRd = registerSelect() + # Header f.write("\n") - f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"("+formatstr.format(CurrAdr+20+8*spacers)+") data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n") + f.write(" # Testcase "+str(TestNum)+"\n") + # Test Code addInst(" JAL x"+str(OtherRd)+", 2f\n") f.write("1:\n") addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n") @@ -118,29 +141,27 @@ def writeBackwardsJumpVector(spacers): f.write("2:\n") for i in range(spacers): addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n") - addInst(" JAL x"+str(rd)+", 1b\n") + if (instr=="JAL"): + addInst(" JAL x"+str(rd)+", 1b\n") + elif (instr=="JALR"): + dist = -20 - 4 - (1+spacers)*(8 if (xlen == 32) else 20) # Compute distance from linked adr to target adr + addJalr(rs,rd,dist); + else: + exit("invalid instruction") LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value f.write("3:\n") - addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n") - f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n") - addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n") - f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n") - writeExpectedToRef(LinkAdr) - writeExpectedToRef(expected) - TestNum = TestNum+1 + # Store values to be verified + expectValue(rd, LinkAdr, 2*TestNum+0) + expectValue(DataReg, expected, 2*TestNum+1) def writeChainVector(repetitions,spacers): global TestNum + TestNum += 1 rd, rs, DataReg,OtherRd = registerSelect() - if (xlen==64): - expected = int("fedbca9876540000",16) - unexpected = int("ffff0000ffff0000",16) - else: - expected = int("fedbca98",16) - unexpected = int("ff00ff00",16) - + # Header f.write("\n") - f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"(ugh; if you really wanted to, you could figure it out) data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n") + f.write(" # Testcase "+str(TestNum)+"\n") + # Test Code addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n") for i in range(repetitions): addInst(" JAL x"+str(OtherRd)+", "+str(3*i+2)+"f\n") @@ -159,57 +180,56 @@ def writeChainVector(repetitions,spacers): for j in range(i): addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n") f.write(str(3*i+3)+":\n") - addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n") - f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n") - addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n") - f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n") - writeExpectedToRef(LinkAdr) - writeExpectedToRef(expected) - TestNum = TestNum+1 - - -def writeExpectedToRef(expected): - global TestGroupSizes - TestGroupSizes[TestGroup-1] += 1 - if (xlen == 32): - r.write(formatrefstr.format(expected)+"\n") - else: - r.write(formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32)+"\n") + # Store values to be verified + expectValue(rd, LinkAdr, 2*TestNum+0) + expectValue(DataReg, expected, 2*TestNum+1) ################################## # main body ################################## # change these to suite your tests -tests = ["JAL"] +test = 0 +tests = ["JAL","JALR"] author = "Ben Bracker (bbracker@hmc.edu)" xlens = [32,64] -numtests = 100; +numtests = 100 # setup seed(0) # make tests reproducible # generate files for each test -for xlen in xlens: - CurrAdr = int("80000108",16) - TestNum = 0 - TestGroup = 1 - TestGroupSizes = [0] - AllRegs = list(range(0,32)) - UnusedRegs = deepcopy(AllRegs) - StoreAdrReg = 6 # matches what's in header script - UnusedRegs.remove(6) +for test in tests: + for xlen in xlens: + print(test+" "+str(xlen)) + CurrAdr = int("80000108",16) + TestNum = -1 + TestGroup = 1 + TestGroupSizes = [0] + AllRegs = list(range(0,32)) + UnusedRegs = deepcopy(AllRegs) + StoreAdrReg = 6 # matches what's in header script + UnusedRegs.remove(6) + if (xlen==64): + expected = int("fedbca9876540000",16) + unexpected = int("ffff0000ffff0000",16) + else: + expected = int("fedbca98",16) + unexpected = int("ff00ff00",16) + + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + imm20formatstr = "{:05x}" + imm12formatstr = "{:03x}" + + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 - formatstrlen = str(int(xlen/4)) - formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number - formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x - if (xlen == 32): - storecmd = "sw" - wordsize = 4 - else: - storecmd = "sd" - wordsize = 8 - for test in tests: imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" basename = "WALLY-" + test fname = imperaspath + "src/" + basename + ".S" @@ -221,7 +241,7 @@ for xlen in xlens: f.write("///////////////////////////////////////////\n") f.write("// "+fname+ "\n") f.write("//\n") - f.write("// This file can be used to test the RISC-V JAL instruction.\n") + f.write("// This file can be used to test the RISC-V JAL(R) instruction.\n") f.write("// But be warned that altering the test environment may break this test!\n") f.write("// In order to work, this test expects that the first instruction (la)\n") f.write("// be allocated at 0x80000100.\n") @@ -235,14 +255,24 @@ for xlen in xlens: f.write(line) # print directed test vectors - for i in range(0,31): - writeForwardsJumpVector(randint(0,4)) - for i in range(0,31): - writeBackwardsJumpVector(randint(0,4)) - writeForwardsJumpVector(100) - writeBackwardsJumpVector(100) - writeChainVector(6,True) - writeChainVector(16,False) + if test == "JAL": + for i in range(0,31): + writeForwardsJumpVector(randint(0,4),"JAL") + for i in range(0,31): + writeBackwardsJumpVector(randint(0,4),"JAL") + writeForwardsJumpVector(100,"JAL") + writeBackwardsJumpVector(100,"JAL") + writeChainVector(6,True) + writeChainVector(16,False) + elif test == "JALR": + for i in range(0,31): + writeForwardsJumpVector(randint(0,4),"JALR") + for i in range(0,31): + writeBackwardsJumpVector(randint(0,4),"JALR") + # can't make these latter two too long else 12 bit immediate overflows + # (would need to lui or slli rs to achieve longer ranges) + writeForwardsJumpVector(15,"JALR") + writeBackwardsJumpVector(15,"JALR") # print footer h = open("testgen_footer.S", "r") @@ -254,7 +284,3 @@ for xlen in xlens: f.write("\nRV_COMPLIANCE_DATA_END\n") f.close() r.close() - - - -