package projet.op

import chisel3._
import chisel3.util.switch
import projet.CUInterface
import projet.AluOpCode
import chisel3.util.is
import projet.OpType

object OpBranch {
// Implements functions for all instruction of the branch kind
    def opBranch(io: CUInterface) = {
        val funct3 = io.instruction(14, 12);

        // Meaning of Funct3 in the context of an OpBranch instruction
        object Funct3 extends ChiselEnum {
            val BEQ = "b000".U
            val BNE = "b001".U
            val BLT = "b100".U
            val BGE = "b101".U
            val BLTU = "b110".U
            val BGEU = "b111".U
        }

        io.optype := OpType.B
        val branch = WireInit(false.B);
        switch(funct3) {
            is(Funct3.BEQ) {
                // Send operands from registers to alu
                io.alu_opcode := AluOpCode.Equal
                io.mux_rega_pc := true.B;
                io.mux_regb_imm := true.B;
                branch := io.alu_comp_result
            }

            is(Funct3.BNE) {
                // Send operands from registers to alu
                io.alu_opcode := AluOpCode.Equal
                io.mux_rega_pc := true.B;
                io.mux_regb_imm := true.B;
                branch := ~io.alu_comp_result
            }

            // Signed comparison
            is(Funct3.BLT) {
                // Send operands from registers to alu
                io.alu_opcode := AluOpCode.LessThanSigned
                io.mux_rega_pc := true.B;
                io.mux_regb_imm := true.B;
                branch := io.alu_comp_result
            }

            is(Funct3.BGE) {
                // Send operands from registers to alu
                io.alu_opcode := AluOpCode.LessThanSigned
                io.mux_rega_pc := true.B;
                io.mux_regb_imm := true.B;
                branch := ~io.alu_comp_result
            }

            // Signed comparison
            is(Funct3.BLTU) {
                // Send operands from registers to alu
                io.alu_opcode := AluOpCode.LessThanUnsigned
                io.mux_rega_pc := true.B;
                io.mux_regb_imm := true.B;
                branch := io.alu_comp_result
            }

            is(Funct3.BGEU) {
                // Send operands from registers to alu
                io.alu_opcode := AluOpCode.LessThanUnsigned
                io.mux_rega_pc := true.B;
                io.mux_regb_imm := true.B;
                branch := ~io.alu_comp_result
            }
        }

        // Branch if comparison is successful
        when(branch) {
            io.mux_pcadder_jalrwriteback := true.B;
            io.mux_incrpc4_imm := false.B;
            io.mux_regpc_executepc := false.B;
            io.is_jump := true.B;
        }
    }
}
