module branchPredictionBuffer(clock,stall,inst_addr,update,branch_result,buffer_addr,buffer_offset, prediction);
    parameter			 PRED_BUFFER_SIZE = 4; // 128 lines with 4 entries/line
    parameter			 PRED_BUFFER_BITS = 2;
    input [PRED_BUFFER_BITS-1:0] inst_addr; // We need to decode up to 4 instructions.
    input			 branch_result; // Result of a branch calculation.
    input [PRED_BUFFER_BITS-1:0] buffer_addr;
    input [1:0]			 buffer_offset;
    input		    clock;
    input		    stall;  // Stalls when instructions are not available.
    input		    update; // Tells the buffer that an update is ready.
    output [3:0]	    prediction; // Prediction bits sent out to decoder stage.
    
    reg [3:0]		    prediction;
    reg [1:0]		    state_bank0 [PRED_BUFFER_SIZE-1:0];
    reg [1:0]		    state_bank1 [PRED_BUFFER_SIZE-1:0];
    reg [1:0]		    state_bank2 [PRED_BUFFER_SIZE-1:0];
    reg [1:0]		    state_bank3 [PRED_BUFFER_SIZE-1:0];


    integer	 i;

    // synopsys translate_off 
    // Always begin in a weak, not taken state
    initial begin
	for (i=0; i<PRED_BUFFER_SIZE; i=i+1) begin
	    state_bank0[i] = 2'b01;
	    state_bank1[i] = 2'b01;
	    state_bank2[i] = 2'b01;
	    state_bank3[i] = 2'b01;
	end // for (i=0; i<PRED_BUFFER_SIZE; i=i+1)
	prediction = 4'b0000;
    end // initial begin


    // synopsys translate_on

    always @(posedge clock) begin
	if (!stall) begin
	    if (state_bank3[inst_addr] > 1)
		prediction[3] = 1;
	    else
		prediction[3] = 0;
	    if (state_bank2[inst_addr] > 1)
		prediction[2] = 1;
	    else
		prediction[2] = 0;
	    if (state_bank1[inst_addr] > 1)
		prediction[1] = 1;
	    else
		prediction[1] = 0;
	    if (state_bank0[inst_addr] > 1)
		prediction[0] = 1;
	    else
		prediction[0] = 0;
	end // if (!stall)
    end // always @ (posedge clock && !stall)


    // Assuming here that reading and updating occur at different parts of
    // the clock cycle. We only need to update one location at a time.
    always @(negedge clock) begin
	if (update) begin
	    if (branch_result) begin // The branch was taken.
		if (buffer_offset == 0)
		    state_bank0[buffer_addr] = state_bank0[buffer_addr] + 1;
		else if (buffer_offset == 1)
		    state_bank1[buffer_addr] = state_bank1[buffer_addr] + 1;
		else if (buffer_offset == 2)
		    state_bank2[buffer_addr] = state_bank2[buffer_addr] + 1;
		else
		    state_bank3[buffer_addr] = state_bank3[buffer_addr] + 1;
	    end // if (branch_result)
	    
	    else begin
		if (buffer_offset == 0)
		    state_bank0[buffer_addr] = state_bank0[buffer_addr] - 1;
		else if (buffer_offset == 1)
		    state_bank1[buffer_addr] = state_bank1[buffer_addr] - 1;
		else if (buffer_offset == 2)
		    state_bank2[buffer_addr] = state_bank2[buffer_addr] - 1;
		else
		    state_bank3[buffer_addr] = state_bank3[buffer_addr] - 1;
	    end // else: !if(branch_result)
	end // if (update)
    end // always @ (negedge clock && !stall && update)


endmodule // branchPredictionBuffer
