2021-02-14 16:47:01 +00:00
///////////////////////////////////////////
// bpred.sv
//
2023-01-19 21:06:37 +00:00
// Written: Ross Thomposn ross1728@gmail.com
// Created: 12 February 2021
// Modified: 19 January 2023
2021-02-14 16:47:01 +00:00
//
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.
2021-02-14 16:47:01 +00:00
//
2023-01-11 23:15:08 +00:00
// A component of the CORE-V-WALLY configurable RISC-V project.
2021-02-14 16:47:01 +00:00
//
2023-01-10 19:35:20 +00:00
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
2021-02-14 16:47:01 +00:00
//
2023-01-10 19:35:20 +00:00
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
2021-02-14 16:47:01 +00:00
//
2023-01-10 19:35:20 +00:00
// 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
2021-02-14 16:47:01 +00:00
//
2023-01-10 19:35:20 +00:00
// 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.
2022-01-07 12:58:40 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////
2021-02-14 16:47:01 +00:00
`include " wally-config.vh "
2023-01-29 21:03:25 +00:00
`define INSTR_CLASS_PRED 1
2023-01-26 01:39:18 +00:00
2022-12-23 03:36:49 +00:00
module bpred (
2023-01-24 14:14:31 +00:00
input logic clk , reset ,
input logic StallF , StallD , StallE , StallM , StallW ,
input logic FlushD , FlushE , FlushM , FlushW ,
2023-01-24 13:42:34 +00:00
// Fetch stage
// the prediction
2023-01-24 14:14:31 +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
2023-01-24 13:42:34 +00:00
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
2023-01-24 13:42:34 +00:00
// Update Predictor
2023-01-24 14:14:31 +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-29 21:24:20 +00:00
input logic [ 31 : 0 ] PostSpillInstrRawF , // Instruction
2023-01-24 13:42:34 +00:00
// Branch and jump outcome
2023-01-29 21:24:20 +00:00
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)
2023-01-24 13:42:34 +00:00
output logic [ 3 : 0 ] InstrClassM , // The valid instruction class. 1-hot encoded as jalr, ret, jr (not ret), j, br
2023-01-29 21:24:20 +00:00
output logic JumpOrTakenBranchM , // The valid instruction class. 1-hot encoded as jalr, ret, jr (not ret), j, br
2022-12-23 03:36:49 +00:00
2023-01-24 13:42:34 +00:00
// Report branch prediction status
output logic BPPredWrongE , // Prediction is wrong
2023-01-29 21:24:20 +00:00
output logic BPPredWrongM , // Prediction is wrong
2023-01-24 13:42:34 +00:00
output logic DirPredictionWrongM , // Prediction direction is wrong
output logic BTBPredPCWrongM , // Prediction target wrong
output logic RASPredPCWrongM , // RAS prediction is wrong
output logic PredictionInstrClassWrongM // Class prediction is wrong
2023-01-29 21:24:20 +00:00
) ;
2021-02-14 16:47:01 +00:00
2023-01-25 18:14:18 +00:00
logic PredValidF ;
2023-01-05 19:36:51 +00:00
logic [ 1 : 0 ] DirPredictionF ;
2021-02-14 16:47:01 +00:00
2023-02-09 00:24:38 +00:00
logic [ 3 : 0 ] BTBPredInstrClassF , PredInstrClassF , PredInstrClassD ;
2023-01-25 22:03:02 +00:00
logic [ `XLEN - 1 : 0 ] PredPCF , RASPCF ;
2021-10-27 19:43:55 +00:00
logic PredictionPCWrongE ;
2023-02-09 00:24:38 +00:00
logic AnyWrongPredInstrClassD , AnyWrongPredInstrClassE ;
2023-01-26 01:39:18 +00:00
logic [ 3 : 0 ] InstrClassF , InstrClassD , InstrClassE , InstrClassW ;
2023-02-09 00:24:38 +00:00
logic DirPredictionWrongE , BTBPredPCWrongE , RASPredPCWrongE ;
2021-03-24 02:49:16 +00:00
2022-12-20 04:46:11 +00:00
logic SelBPPredF ;
logic [ `XLEN - 1 : 0 ] BPPredPCF ;
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 ;
2023-01-14 00:05:47 +00:00
logic [ 3 : 0 ] WrongPredInstrClassD ;
2023-01-26 19:21:16 +00:00
logic BTBTargetWrongE ;
logic RASTargetWrongE ;
logic JumpOrTakenBranchE ;
logic [ `XLEN - 1 : 0 ] PredPCD , PredPCE , RASPCD , RASPCE ;
2021-03-04 15:23:35 +00:00
// Part 1 branch direction prediction
2022-12-20 18:58:54 +00:00
// look into the 2 port Sram model. something is wrong.
2023-01-29 04:06:12 +00:00
if ( `BPRED_TYPE = = " BPTWOBIT " ) begin : Predictor
2023-01-29 22:26:44 +00:00
twoBitPredictor # ( `BPRED_SIZE ) 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
2023-01-29 04:06:12 +00:00
end else if ( `BPRED_TYPE = = " BPGLOBAL " ) begin : Predictor
2023-01-29 22:26:44 +00:00
globalhistory # ( `BPRED_SIZE ) 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:41:55 +00:00
. BranchInstrE ( InstrClassE [ 0 ] ) , . BranchInstrM ( InstrClassM [ 0 ] ) , . PCSrcE ) ;
2021-03-16 20:06:40 +00:00
2023-01-29 04:06:12 +00:00
end else if ( `BPRED_TYPE = = " BPSPECULATIVEGLOBAL " ) begin : Predictor
2023-01-29 22:26:44 +00:00
speculativeglobalhistory # ( `BPRED_SIZE ) DirPredictor ( . clk , . reset , . StallF , . StallD , . StallE , . StallM , . StallW , . FlushD , . FlushE , . FlushM , . FlushW ,
. DirPredictionF , . DirPredictionWrongE ,
2023-02-09 20:48:02 +00:00
. PredInstrClassF , . InstrClassD , . InstrClassE , . WrongPredInstrClassD , . PCSrcE ) ;
2023-01-25 22:03:02 +00:00
2023-01-29 04:06:12 +00:00
end else if ( `BPRED_TYPE = = " BPGSHARE " ) begin : Predictor
2023-01-29 22:26:44 +00:00
gshare # ( `BPRED_SIZE ) DirPredictor ( . clk , . reset , . StallF , . StallD , . StallE , . StallM , . FlushD , . FlushE , . FlushM ,
2023-01-25 23:06:25 +00:00
. PCNextF , . PCE , . 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
2023-01-29 04:06:12 +00:00
end else if ( `BPRED_TYPE = = " BPSPECULATIVEGSHARE " ) begin : Predictor
2023-01-29 22:26:44 +00:00
speculativegshare # ( `BPRED_SIZE ) DirPredictor ( . clk , . reset , . StallF , . StallD , . StallE , . StallM , . StallW , . FlushD , . FlushE , . FlushM , . FlushW ,
2023-02-01 16:27:58 +00:00
. PCNextF , . PCF , . PCD , . PCE , . DirPredictionF , . DirPredictionWrongE ,
2023-01-31 05:55:52 +00:00
. PredInstrClassF , . InstrClassD , . InstrClassE , . WrongPredInstrClassD , . PCSrcE ) ;
2023-01-05 20:18:00 +00:00
2023-01-29 04:06:12 +00:00
end else if ( `BPRED_TYPE = = " BPLOCALPAg " ) begin : Predictor
2023-01-05 20:04:09 +00:00
// *** 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 ,
2023-01-05 20:04:09 +00:00
. UpdatePrediction ( InstrClassE [ 0 ] ) ) ;
- - - - - / \ - - - - - EXCLUDED - - - - - / \ - - - - - */
2022-01-05 16:25:08 +00:00
end
2021-03-16 20:06:40 +00:00
2021-03-04 15:23:35 +00:00
// Part 2 Branch target address prediction
2023-02-09 00:24:38 +00:00
// BTB contains target address for all CFI
2021-02-14 16:47:01 +00:00
2023-01-25 22:03:02 +00:00
btb TargetPredictor ( . clk , . reset , . StallF , . StallD , . StallM , . FlushD , . FlushM ,
. PCNextF , . PCF , . PCD , . PCE ,
. PredPCF ,
2023-01-26 01:39:18 +00:00
. BTBPredInstrClassF ,
2023-01-25 18:14:18 +00:00
. PredValidF ,
2023-02-09 00:24:38 +00:00
. AnyWrongPredInstrClassE ,
2023-01-24 22:12:35 +00:00
. IEUAdrE ,
2023-02-01 04:03:51 +00:00
. InstrClassD ,
2023-01-24 22:12:35 +00:00
. InstrClassE ) ;
2021-02-14 16:47:01 +00:00
2022-02-01 20:32:27 +00:00
// the branch predictor needs a compact decoding of the instruction class.
2023-01-26 01:39:18 +00:00
if ( `INSTR_CLASS_PRED = = 0 ) begin : DirectClassDecode
logic [ 4 : 0 ] CompressedOpcF ;
logic [ 3 : 0 ] InstrClassF ;
logic cjal , cj , cjr , cjalr ;
assign CompressedOpcF = { PostSpillInstrRawF [ 1 : 0 ] , PostSpillInstrRawF [ 15 : 13 ] } ;
assign cjal = CompressedOpcF = = 5 'h09 & `XLEN = = 32 ;
assign cj = CompressedOpcF = = 5 'h0d ;
assign cjr = CompressedOpcF = = 5 'h14 & ~ PostSpillInstrRawF [ 12 ] & PostSpillInstrRawF [ 6 : 2 ] = = 5 'b0 & PostSpillInstrRawF [ 11 : 7 ] ! = 5 'b0 ;
assign cjalr = CompressedOpcF = = 5 'h14 & PostSpillInstrRawF [ 12 ] & PostSpillInstrRawF [ 6 : 2 ] = = 5 'b0 & PostSpillInstrRawF [ 11 : 7 ] ! = 5 'b0 ;
assign InstrClassF [ 0 ] = PostSpillInstrRawF [ 6 : 0 ] = = 7 'h63 |
2023-01-26 18:19:33 +00:00
( `C_SUPPORTED & CompressedOpcF [ 4 : 1 ] = = 4 'h7 ) ;
2023-01-26 01:39:18 +00:00
assign InstrClassF [ 1 ] = ( PostSpillInstrRawF [ 6 : 0 ] = = 7 'h67 & ( PostSpillInstrRawF [ 19 : 15 ] & 5 'h1B ) ! = 5 'h01 & ( PostSpillInstrRawF [ 11 : 7 ] & 5 'h1B ) ! = 5 'h01 ) | // jump register, but not return
( PostSpillInstrRawF [ 6 : 0 ] = = 7 'h6F & ( PostSpillInstrRawF [ 11 : 7 ] & 5 'h1B ) ! = 5 'h01 ) | // jump, RD != x1 or x5
( `C_SUPPORTED & ( cj | ( cjr & ( ( PostSpillInstrRawF [ 11 : 7 ] & 5 'h1B ) ! = 5 'h01 ) ) ) ) ;
assign InstrClassF [ 2 ] = PostSpillInstrRawF [ 6 : 0 ] = = 7 'h67 & ( PostSpillInstrRawF [ 19 : 15 ] & 5 'h1B ) = = 5 'h01 | // return must return to ra or r5
( `C_SUPPORTED & ( cjalr | cjr ) & ( ( PostSpillInstrRawF [ 11 : 7 ] & 5 'h1B ) = = 5 'h01 ) ) ;
assign InstrClassF [ 3 ] = ( ( PostSpillInstrRawF [ 6 : 0 ] & 7 'h77 ) = = 7 'h67 & ( PostSpillInstrRawF [ 11 : 07 ] & 5 'h1B ) = = 5 'h01 ) | // jal(r) must link to ra or x5
2023-01-26 17:07:47 +00:00
( `C_SUPPORTED & ( cjal | ( cjalr & ( PostSpillInstrRawF [ 11 : 7 ] & 5 'h1b ) = = 5 'h01 ) ) ) ;
2023-01-26 01:39:18 +00:00
assign PredInstrClassF = InstrClassF ;
2023-01-26 16:54:43 +00:00
assign SelBPPredF = ( PredInstrClassF [ 0 ] & DirPredictionF [ 1 ] ) |
PredInstrClassF [ 2 ] |
2023-02-01 16:59:38 +00:00
PredInstrClassF [ 1 ] |
PredInstrClassF [ 3 ] ;
2023-01-26 01:39:18 +00:00
end else begin
assign PredInstrClassF = BTBPredInstrClassF ;
2023-01-26 16:54:43 +00:00
assign SelBPPredF = ( PredInstrClassF [ 0 ] & DirPredictionF [ 1 ] & PredValidF ) |
PredInstrClassF [ 2 ] |
2023-02-01 16:59:38 +00:00
( PredInstrClassF [ 1 ] & PredValidF ) |
( PredInstrClassF [ 3 ] & PredValidF ) ;
2023-01-26 01:39:18 +00:00
end
2023-01-31 05:55:52 +00:00
// Part 3 RAS
RASPredictor RASPredictor ( . clk , . reset , . StallF , . StallD , . StallE , . StallM , . FlushD , . FlushE , . FlushM ,
. PredInstrClassF , . InstrClassD , . InstrClassE ,
. WrongPredInstrClassD , . RASPCF , . PCLinkE ) ;
assign BPPredPCF = PredInstrClassF [ 2 ] ? RASPCF : PredPCF ;
2023-01-26 01:39:18 +00:00
2023-01-13 21:19:53 +00:00
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
2023-01-31 05:55:52 +00:00
2023-01-13 21:19:53 +00:00
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-02-09 00:24:38 +00:00
{ DirPredictionWrongE , BTBPredPCWrongE , RASPredPCWrongE , AnyWrongPredInstrClassE } ,
2023-01-05 23:19:27 +00:00
{ DirPredictionWrongM , BTBPredPCWrongM , RASPredPCWrongM , PredictionInstrClassWrongM } ) ;
2022-02-01 20:32:27 +00:00
2021-02-14 16:47:01 +00:00
// pipeline the class
2023-01-13 21:19:53 +00:00
flopenrc # ( 4 ) PredInstrClassRegD ( clk , reset , FlushD , ~ StallD , PredInstrClassF , PredInstrClassD ) ;
2023-02-09 00:24:38 +00:00
flopenrc # ( 1 ) WrongInstrClassRegE ( clk , reset , FlushE , ~ StallE , AnyWrongPredInstrClassD , AnyWrongPredInstrClassE ) ;
2021-03-31 16:54:02 +00:00
2022-12-23 02:33:38 +00:00
// Check the prediction
2023-02-07 20:01:59 +00:00
// if it is a CFI then check if the next instruction address (PCD) matches the branch's target or fallthrough address.
// if the class prediction is wrong a regular instruction may have been predicted as a taken branch
// this will result in PCD not being equal to the fall through address PCLinkE (PCE+4).
// The next instruction is always valid as no other flush would occur at the same time as the branch and not
// also flush the branch. This will change in a superscaler cpu.
assign PredictionPCWrongE = PCCorrectE ! = PCD ;
2023-02-09 00:24:38 +00:00
// branch class prediction wrong.
assign WrongPredInstrClassD = PredInstrClassD ^ InstrClassD ;
assign AnyWrongPredInstrClassD = | WrongPredInstrClassD ;
// Finally indicate if the branch predictor was wrong
assign BPPredWrongE = PredictionPCWrongE & ( | InstrClassE | AnyWrongPredInstrClassE ) ;
2023-02-07 20:01:59 +00:00
// Output the predicted PC or corrected PC on miss-predict.
// Selects the BP or PC+2/4.
mux2 # ( `XLEN ) pcmux0 ( PCPlus2or4F , BPPredPCF , SelBPPredF , PCNext0F ) ;
// If the prediction is wrong select the correct address.
mux2 # ( `XLEN ) pcmux1 ( PCNext0F , PCCorrectE , BPPredWrongE , PCNext1F ) ;
// Correct branch/jump target.
mux2 # ( `XLEN ) pccorrectemux ( PCLinkE , IEUAdrE , PCSrcE , PCCorrectE ) ;
2021-03-31 16:54:02 +00:00
2023-02-07 20:01:59 +00:00
// If the fence/csrw was predicted as a taken branch then we select PCF, rather PCE.
// Effectively this is PCM+4 or the non-existant PCLinkM
if ( `INSTR_CLASS_PRED ) mux2 # ( `XLEN ) pcmuxBPWrongInvalidateFlush ( PCE , PCF , BPPredWrongM , NextValidPCE ) ;
else assign NextValidPCE = PCE ;
2023-01-25 23:06:25 +00:00
// performance counters
2023-01-26 19:21:16 +00:00
// 1. class (class wrong / minstret) (PredictionInstrClassWrongM / csr) // Correct now
2023-01-25 23:06:25 +00:00
// 2. target btb (btb target wrong / class[0,1,3]) (btb target wrong / (br + j + jal)
// 3. target ras (ras target wrong / class[2])
// 4. direction (br dir wrong / class[0])
2023-02-09 00:24:38 +00:00
// Unforuantely we can't relay on PCD to infer the correctness of the BTB or RAS because the class prediction
// could be wrong or the fall through address selected for branch predict not taken.
// By pipeline the BTB's PC and RAS address through the pipeline we can measure the accuracy of
// both without the above inaccuracies.
assign BTBPredPCWrongE = ( PredPCE ! = IEUAdrE ) & ( InstrClassE [ 0 ] | InstrClassE [ 1 ] | InstrClassE [ 3 ] ) & PCSrcE ;
assign RASPredPCWrongE = ( RASPCE ! = IEUAdrE ) & InstrClassE [ 2 ] & PCSrcE ;
2023-01-26 19:21:16 +00:00
assign JumpOrTakenBranchE = ( InstrClassE [ 0 ] & PCSrcE ) | InstrClassE [ 1 ] | InstrClassE [ 3 ] ;
2023-02-09 00:24:38 +00:00
flopenrc # ( 1 ) JumpOrTakenBranchMReg ( clk , reset , FlushM , ~ StallM , JumpOrTakenBranchE , JumpOrTakenBranchM ) ;
2023-01-26 19:21:16 +00:00
flopenrc # ( `XLEN ) BTBTargetDReg ( clk , reset , FlushD , ~ StallD , PredPCF , PredPCD ) ;
flopenrc # ( `XLEN ) BTBTargetEReg ( clk , reset , FlushE , ~ StallE , PredPCD , PredPCE ) ;
flopenrc # ( `XLEN ) RASTargetDReg ( clk , reset , FlushD , ~ StallD , RASPCF , RASPCD ) ;
flopenrc # ( `XLEN ) RASTargetEReg ( clk , reset , FlushE , ~ StallE , RASPCD , RASPCE ) ;
2022-12-20 18:58:54 +00:00
2021-02-14 21:06:53 +00:00
endmodule