This section covers all information needed to implement Task 3: Static Branch Predictor. We first determined the what strategy our branch predictor would use. Then, we determined how our processor would handle a misprediction. Finally, we implemented this design and included performance counters to monitor the accuracy of our predictions.
A static branch predictor follows one of two strategies: always-not-taken or always-taken. Like the names suggest, always-not-taken assumes the branch condition is always false, and always-taken assumes the branch condition is always true.
For our branch, we chose to implement always-not-taken. We chose this strategy because it allows our program to continue executing line by line, as though the branch never happened. Then, only when we are incorrect, do we need to update the PC. If we had used always-taken, we would have had to implement an additional component, the branch target buffer (BTB). The BTB would have to be in the IF stage so that it can quickly identify if the current instruction is a branch, and determine the corresponding branch target. Then, the always-not-taken strategy would always have to update the PC to take the branch, and update the PC again if the branch condition was false.
As briefly mentioned before, because we decided to use always-not-taken, we simply continue execution as if nothing happened. When a misprediction occurs, we flush the IF/ID pipeline register and update the PC to the correct address immediately (PC = PC + 4 + immediate).
ImplementationEditOur branch predictor was implemented as its own block. The block takes in a control input bit branch, two register values on the input buses read_data_1(31..0) and read_data_2(31..0), the current PC on the input bus pc(9..0), and the immediate value on the input bus sign_ext(31..0). The block immediately cacluates the next PC address, as well as the branch address. Then, when branch is set to '1', the branch predictor executes a XOR operation between read_data_1'(31..0) and read_data_2(31..0). If the result of that operation is '0', then we know the two register values are equal, meaning that our BEQ condition is true. When this occurs, we output a signal branch_taken as '1', and output a bus branch_address(7..0) with the branch address. Otherwise, when the condition is false, branch_taken is '0', and branch_address(7..0) contains the next PC address.
Finally, we implemented very basic counter blocks to track the number of times a branch instruction occurs, and then the number of times the branch was taken. These are very basic blocks that take an input signal signal_in, the clock signal clock, and a reset signal reset. When clock changes to be '1', signal_in is checked. When signal_in is '1', a counter signal counter_reg(9..0) is incremented by 1. Then the block outputs the count tally on the output bus total(9..0). When reset is set to '1', counter_reg(9..0) is reset to 0.
<Verification for this task can be viewed in Final Report. We will also include it here when we are able. Thank you for your patience.>