cvw/pipelined/src/ifu/bpred.sv

238 lines
12 KiB
Systemverilog
Raw Normal View History

///////////////////////////////////////////
// bpred.sv
//
2023-01-19 21:06:37 +00:00
// Written: Ross Thomposn ross1728@gmail.com
// Created: 12 February 2021
// Modified: 19 January 2023
//
2023-01-19 21:06:37 +00:00
// Purpose: Branch direction prediction and jump/branch target prediction.
// Prediction made during the fetch stage and corrected in the execution stage.
//
2023-01-11 23:15:08 +00:00
// A component of the CORE-V-WALLY configurable RISC-V project.
//
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
// may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work distributed under the
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
`include "wally-config.vh"
module bpred (
input logic clk, reset,
input logic StallF, StallD, StallE, StallM, StallW,
input logic FlushD, FlushE, FlushM, FlushW,
// Fetch stage
// the prediction
2023-01-19 21:06:37 +00:00
input logic [31:0] InstrD, // Decompressed decode stage instruction. Used to decode instruction class
input logic [`XLEN-1:0] PCNextF, // Next Fetch Address
input logic [`XLEN-1:0] PCPlus2or4F, // PCF+2/4
output logic [`XLEN-1:0] PCNext1F, // Branch Predictor predicted or corrected fetch address on miss prediction
output logic [`XLEN-1:0] NextValidPCE, // Address of next valid instruction after the instruction in the Memory stage.
2022-12-20 04:51:55 +00:00
// Update Predictor
2023-01-19 21:06:37 +00:00
input logic [`XLEN-1:0] PCF, // Fetch stage instruction address.
input logic [`XLEN-1:0] PCD, // Decode stage instruction address. Also the address the branch predictor took.
input logic [`XLEN-1:0] PCE, // Execution stage instruction address.
input logic [`XLEN-1:0] PCM, // Memory stage instruction address.
2022-12-20 04:51:55 +00:00
2023-01-19 21:06:37 +00:00
// Branch and jump outcome
input logic PCSrcE, // Executation stage branch is taken
input logic [`XLEN-1:0] IEUAdrE, // The branch/jump target address
input logic [`XLEN-1:0] PCLinkE, // The address following the branch instruction. (AKA Fall through address)
output logic [3:0] InstrClassM, // The valid instruction class. 1-hot encoded as jalr, ret, jr (not ret), j, br
// Report branch prediction status
2023-01-19 21:06:37 +00:00
output logic BPPredWrongE, // Prediction is wrong.
output logic DirPredictionWrongM, // Prediction direction is wrong.
output logic BTBPredPCWrongM, // Prediction target wrong.
output logic RASPredPCWrongM, // RAS prediction is wrong.
2023-01-05 23:19:27 +00:00
output logic PredictionInstrClassWrongM // Class prediction is wrong.
);
2021-10-27 19:43:55 +00:00
logic BTBValidF;
2023-01-05 19:36:51 +00:00
logic [1:0] DirPredictionF;
logic [3:0] PredInstrClassF, PredInstrClassD, PredInstrClassE;
2021-10-27 19:43:55 +00:00
logic [`XLEN-1:0] BTBPredPCF, RASPCF;
logic TargetWrongE;
logic FallThroughWrongE;
logic PredictionPCWrongE;
logic PredictionInstrClassWrongE;
logic [3:0] InstrClassD, InstrClassE, InstrClassW;
2023-01-05 19:36:51 +00:00
logic DirPredictionWrongE, BTBPredPCWrongE, RASPredPCWrongE, BPPredClassNonCFIWrongE;
2021-03-24 02:49:16 +00:00
logic SelBPPredF;
logic [`XLEN-1:0] BPPredPCF;
2022-12-20 04:51:55 +00:00
logic BPPredWrongM;
2022-12-20 05:16:58 +00:00
logic [`XLEN-1:0] PCNext0F;
2022-12-20 18:58:54 +00:00
logic [`XLEN-1:0] PCCorrectE;
logic [3:0] WrongPredInstrClassD;
// Part 1 branch direction prediction
2022-12-20 18:58:54 +00:00
// look into the 2 port Sram model. something is wrong.
2022-01-05 16:25:08 +00:00
if (`BPTYPE == "BPTWOBIT") begin:Predictor
2023-01-05 19:27:22 +00:00
twoBitPredictor DirPredictor(.clk, .reset, .StallF, .StallD, .StallE, .StallM, .FlushD, .FlushE, .FlushM,
2023-01-05 19:36:51 +00:00
.PCNextF, .PCM, .DirPredictionF, .DirPredictionWrongE,
2023-01-05 19:27:22 +00:00
.BranchInstrE(InstrClassE[0]), .BranchInstrM(InstrClassM[0]), .PCSrcE);
2021-03-16 20:06:40 +00:00
2022-01-05 16:25:08 +00:00
end else if (`BPTYPE == "BPGLOBAL") begin:Predictor
globalhistory DirPredictor(.clk, .reset, .StallF, .StallD, .StallE, .StallM, .FlushD, .FlushE, .FlushM,
2023-01-05 19:36:51 +00:00
.PCNextF, .PCM, .DirPredictionF, .DirPredictionWrongE,
.BranchInstrE(InstrClassE[0]), .BranchInstrM(InstrClassM[0]), .PCSrcE);
2021-03-16 20:06:40 +00:00
end else if (`BPTYPE == "BPSPECULATIVEGLOBAL") begin:Predictor
speculativeglobalhistory #(10) DirPredictor(.clk, .reset, .StallF, .StallD, .StallE, .StallM, .StallW, .FlushD, .FlushE, .FlushM, .FlushW,
.PCNextF, .PCF, .PCD, .PCE, .PCM, .DirPredictionF, .DirPredictionWrongE,
.BranchInstrF(PredInstrClassF[0]), .BranchInstrD(InstrClassD[0]), .BranchInstrE(InstrClassE[0]), .BranchInstrM(InstrClassM[0]),
.BranchInstrW(InstrClassW[0]), .PCSrcE);
2022-01-05 16:25:08 +00:00
end else if (`BPTYPE == "BPGSHARE") begin:Predictor
2023-01-05 05:51:09 +00:00
gshare DirPredictor(.clk, .reset, .StallF, .StallD, .StallE, .StallM, .FlushD, .FlushE, .FlushM,
2023-01-05 19:36:51 +00:00
.PCNextF, .PCM, .DirPredictionF, .DirPredictionWrongE,
2023-01-05 05:51:09 +00:00
.BranchInstrE(InstrClassE[0]), .BranchInstrM(InstrClassM[0]), .PCSrcE);
2023-01-05 20:18:00 +00:00
end else if (`BPTYPE == "BPSPECULATIVEGSHARE") begin:Predictor
speculativegshare DirPredictor(.clk, .reset, .StallF, .StallD, .StallE, .StallM, .StallW, .FlushD, .FlushE, .FlushM, .FlushW,
.PCNextF, .PCF, .PCD, .PCE, .PCM, .DirPredictionF, .DirPredictionWrongE,
.BranchInstrF(PredInstrClassF[0]), .BranchInstrD(InstrClassD[0]), .BranchInstrE(InstrClassE[0]), .BranchInstrM(InstrClassM[0]),
2023-01-14 00:50:01 +00:00
.BranchInstrW(InstrClassW[0]), .WrongPredInstrClassD, .PCSrcE);
2023-01-05 20:18:00 +00:00
end else if (`BPTYPE == "BPLOCALPAg") begin:Predictor
// *** Fix me
/* -----\/----- EXCLUDED -----\/-----
2022-02-01 20:32:27 +00:00
localHistoryPredictor DirPredictor(.clk,
2022-12-11 22:28:11 +00:00
.reset, .StallF, .StallE,
2022-01-05 16:25:08 +00:00
.LookUpPC(PCNextF),
2023-01-05 19:27:22 +00:00
.Prediction(DirPredictionF),
2022-01-05 16:25:08 +00:00
// update
.UpdatePC(PCE),
.UpdateEN(InstrClassE[0] & ~StallE),
2022-02-01 20:32:27 +00:00
.PCSrcE,
.UpdatePrediction(InstrClassE[0]));
-----/\----- EXCLUDED -----/\----- */
2022-01-05 16:25:08 +00:00
end
2021-03-16 20:06:40 +00:00
// this predictor will have two pieces of data,
// 1) A direction (1 = Taken, 0 = Not Taken)
// 2) Any information which is necessary for the predictor to build its next state.
// For a 2 bit table this is the prediction count.
assign SelBPPredF = (PredInstrClassF[0] & DirPredictionF[1] & BTBValidF) |
PredInstrClassF[2] |
(PredInstrClassF[1] & BTBValidF) ;
// Part 2 Branch target address prediction
// *** For now the BTB will house the direct and indirect targets
2021-03-24 02:49:16 +00:00
// *** getting to many false positivies from the BTB, we need a partial TAG to reduce this.
BTBPredictor TargetPredictor(.clk(clk),
2021-10-27 19:43:55 +00:00
.reset(reset),
.*, // Stalls and flushes
.LookUpPC(PCNextF),
.TargetPC(BTBPredPCF),
.InstrClass(PredInstrClassF),
2021-10-27 19:43:55 +00:00
.Valid(BTBValidF),
// update
.UpdateEN((|InstrClassE | (PredictionInstrClassWrongE)) & ~StallE),
.UpdatePC(PCE),
.UpdateTarget(IEUAdrE),
2021-10-27 19:43:55 +00:00
.UpdateInvalid(PredictionInstrClassWrongE),
.UpdateInstrClass(InstrClassE));
// Part 3 RAS
// *** need to add the logic to restore RAS on flushes. We will use incr for this.
// *** needs to include flushX
RASPredictor RASPredictor(.clk(clk),
2021-10-27 19:43:55 +00:00
.reset(reset),
2023-01-13 21:56:10 +00:00
.PopF(PredInstrClassF[2] & ~StallF),
.WrongPredInstrClassD,
.InstrClassD,
2023-01-13 21:56:10 +00:00
.RASPCF,
.PushE(InstrClassE[3] & ~StallE),
2021-10-27 19:43:55 +00:00
.incr(1'b0),
2023-01-13 21:56:10 +00:00
.PCLinkE);
assign BPPredPCF = PredInstrClassF[2] ? RASPCF : BTBPredPCF;
2022-02-01 20:32:27 +00:00
// the branch predictor needs a compact decoding of the instruction class.
assign InstrClassD[3] = (InstrD[6:0] & 7'h77) == 7'h67 & (InstrD[11:07] & 5'h1B) == 5'h01; // jal(r) must link to ra or x5
assign InstrClassD[2] = InstrD[6:0] == 7'h67 & (InstrD[19:15] & 5'h1B) == 5'h01; // return must return to ra or r5
assign InstrClassD[1] = (InstrD[6:0] == 7'h67 & (InstrD[19:15] & 5'h1B) != 5'h01 & (InstrD[11:7] & 5'h1B) != 5'h01) | // jump register, but not return
(InstrD[6:0] == 7'h6F & (InstrD[11:7] & 5'h1B) != 5'h01); // jump, RD != x1 or x5
2022-02-01 20:32:27 +00:00
assign InstrClassD[0] = InstrD[6:0] == 7'h63; // branch
flopenrc #(4) InstrClassRegE(clk, reset, FlushE, ~StallE, InstrClassD, InstrClassE);
flopenrc #(4) InstrClassRegM(clk, reset, FlushM, ~StallM, InstrClassE, InstrClassM);
flopenrc #(4) InstrClassRegW(clk, reset, FlushW, ~StallW, InstrClassM, InstrClassW);
2022-12-23 02:33:38 +00:00
flopenrc #(1) BPPredWrongMReg(clk, reset, FlushM, ~StallM, BPPredWrongE, BPPredWrongM);
2022-02-01 20:32:27 +00:00
// branch predictor
2022-12-23 02:33:38 +00:00
flopenrc #(4) BPPredWrongRegM(clk, reset, FlushM, ~StallM,
2023-01-05 23:19:27 +00:00
{DirPredictionWrongE, BTBPredPCWrongE, RASPredPCWrongE, PredictionInstrClassWrongE},
{DirPredictionWrongM, BTBPredPCWrongM, RASPredPCWrongM, PredictionInstrClassWrongM});
2022-02-01 20:32:27 +00:00
// pipeline the class
flopenrc #(4) PredInstrClassRegD(clk, reset, FlushD, ~StallD, PredInstrClassF, PredInstrClassD);
flopenrc #(4) PredInstrClassRegE(clk, reset, FlushE, ~StallE, PredInstrClassD, PredInstrClassE);
2022-12-23 02:33:38 +00:00
// Check the prediction
// first check if the target or fallthrough address matches what was predicted.
assign TargetWrongE = IEUAdrE != PCD;
assign FallThroughWrongE = PCLinkE != PCD;
// If the target is taken check the target rather than fallthrough. The instruction needs to be a branch if PCSrcE is selected
// Remember the bpred can incorrectly predict a non cfi instruction as a branch taken. If the real instruction is non cfi
2021-08-27 20:00:40 +00:00
// it must have selected the fall through.
assign PredictionPCWrongE = (PCSrcE & (|InstrClassE) ? TargetWrongE : FallThroughWrongE);
// The branch direction also need to checked.
// However if the direction is wrong then the pc will be wrong. This is only relavent to checking the
// accuracy of the direciton prediction.
2023-01-05 19:36:51 +00:00
//assign DirPredictionWrongE = (BPPredE[1] ^ PCSrcE) & InstrClassE[0];
// Finally we need to check if the class is wrong. When the class is wrong the BTB needs to be updated.
// Also we want to track this in a performance counter.
assign PredictionInstrClassWrongE = InstrClassE != PredInstrClassE;
// We want to output to the instruction fetch if the PC fetched was wrong. If by chance the predictor was wrong about
// the direction or class, but correct about the target we don't have the flush the pipeline. However we still
// need this information to verify the accuracy of the predictors.
assign BPPredWrongE = (PredictionPCWrongE & |InstrClassE) | BPPredClassNonCFIWrongE;
// If we have a jump, jump register or jal or jalr and the PC is wrong we need to increment the performance counter.
assign BTBPredPCWrongE = (InstrClassE[3] | InstrClassE[1]) & PredictionPCWrongE;
// similar with RAS
assign RASPredPCWrongE = InstrClassE[2] & PredictionPCWrongE;
// Finally if the real instruction class is non CFI but the predictor said it was we need to count.
assign BPPredClassNonCFIWrongE = PredictionInstrClassWrongE & ~|InstrClassE;
// branch class prediction wrong.
assign WrongPredInstrClassD = PredInstrClassD ^ InstrClassD;
2023-01-05 23:19:27 +00:00
2022-12-20 18:58:54 +00:00
// Selects the BP or PC+2/4.
2022-12-23 02:33:38 +00:00
mux2 #(`XLEN) pcmux0(PCPlus2or4F, BPPredPCF, SelBPPredF, PCNext0F);
2022-12-20 18:58:54 +00:00
// If the prediction is wrong select the correct address.
2022-12-23 02:33:38 +00:00
mux2 #(`XLEN) pcmux1(PCNext0F, PCCorrectE, BPPredWrongE, PCNext1F);
2022-12-20 18:58:54 +00:00
// Correct branch/jump target.
2022-12-23 02:33:38 +00:00
mux2 #(`XLEN) pccorrectemux(PCLinkE, IEUAdrE, PCSrcE, PCCorrectE);
2022-12-20 18:58:54 +00:00
2022-12-20 05:16:58 +00:00
// If the fence/csrw was predicted as a taken branch then we select PCF, rather PCE.
2022-12-23 02:33:38 +00:00
// Effectively this is PCM+4 or the non-existant PCLinkM
// if(`BPCLASS) begin
mux2 #(`XLEN) pcmuxBPWrongInvalidateFlush(PCE, PCF, BPPredWrongM, NextValidPCE);
// end else begin
// assign NextValidPCE = PCE;
// end
2022-12-20 18:58:54 +00:00
endmodule