// G-Share Branch Predictor Reference Solution
// 7-bit PC, 7-bit GHR, 128-entry PHT with 2-bit saturating counters

module gshare_predictor(
    input clk,
    input areset,
    
    // Prediction interface
    input predict_valid,
    input [6:0] predict_pc,
    output predict_taken,
    output reg [6:0] predict_history,
    
    // Training interface
    input train_valid,
    input train_taken,
    input train_mispredicted,
    input [6:0] train_history,
    input [6:0] train_pc
);
    
    // Pattern History Table: 128 entries of 2-bit saturating counters
    reg [1:0] pht [0:127];
    
    // Compute PHT indices using XOR
    wire [6:0] predict_index = predict_pc ^ predict_history;
    wire [6:0] train_index = train_pc ^ train_history;
    
    // Prediction output: taken if MSB of counter is 1
    assign predict_taken = pht[predict_index][1];
    
    // PHT update logic (separate from reset for Verilator compatibility)
    integer i;
    
    // GHR sequential logic
    always @(posedge clk or posedge areset) begin
        if (areset) begin
            predict_history <= 7'b0;
        end else begin
            // GHR update: training misprediction takes priority
            if (train_valid && train_mispredicted) begin
                // Recover GHR to state after mispredicting branch
                predict_history <= {train_history[5:0], train_taken};
            end else if (predict_valid) begin
                // Shift in predicted direction
                predict_history <= {predict_history[5:0], predict_taken};
            end
        end
    end
    
    // PHT reset and update logic
    // Using generate loop for reset to satisfy Verilator
    genvar g;
    generate
        for (g = 0; g < 128; g = g + 1) begin : pht_logic
            always @(posedge clk or posedge areset) begin
                if (areset) begin
                    pht[g] <= 2'b01;  // Weakly not-taken
                end else if (train_valid && (train_index == g)) begin
                    // Update this entry
                    if (train_taken) begin
                        // Saturating increment
                        if (pht[g] != 2'b11)
                            pht[g] <= pht[g] + 1;
                    end else begin
                        // Saturating decrement
                        if (pht[g] != 2'b00)
                            pht[g] <= pht[g] - 1;
                    end
                end
            end
        end
    endgenerate
    
endmodule
