`timescale 1ns / 1ps

module ctrsignal(
    input  [ 6:0] OP,
    input  [ 2:0] func3,
    input  [ 6:0] func7,
    
    output [ 4:0] ExtOp,
    output [ 1:0] ALUAsrc,
    output [ 2:0] ALUBsrc,
    output [10:0] ALUctr,
    output        RegWr,
    output        MemtoReg,
    output        MemWr,
    output [ 5:0] Branch,
    output [ 1:0] Jump,
    output [ 2:0] Store,
    output [ 4:0] Load,
    output        shamt
    );

    wire u_type;
    wire j_type;
    wire s_type;
    wire i_type;
    wire b_type;
    wire r_type;
    
    wire instr_lui  ;
    wire instr_auipc;
    wire instr_jal  ;
    wire instr_jalr ;
    wire instr_beq  ;
    wire instr_bne  ;
    wire instr_blt  ;
    wire instr_bge  ;
    wire instr_bltu ;
    wire instr_bgeu ;
    wire instr_lb   ;
    wire instr_lh   ;
    wire instr_lw   ;
    wire instr_lbu  ;
    wire instr_lhu  ;
    wire instr_sb   ;
    wire instr_sh   ;
    wire instr_sw   ;
    wire instr_addi ;
    wire instr_slti ;
    wire instr_sltiu;
    wire instr_xori ;
    wire instr_ori  ;
    wire instr_andi ;
    wire instr_slli ;
    wire instr_srli ;
    wire instr_srai ;
    wire instr_add  ;
    wire instr_sub  ;
    wire instr_sll  ;
    wire instr_slt  ;
    wire instr_sltu ;
    wire instr_xor  ;
    wire instr_srl  ;
    wire instr_sra  ;
    wire instr_or   ;
    wire instr_and  ;

    assign u_type = (OP == 7'b0110111) || (OP == 7'b0010111);
    assign j_type = (OP == 7'b1101111);
    assign s_type = (OP == 7'b0100011);
    assign i_type = (OP == 7'b1100111) || (OP == 7'b0000011) ||(OP == 7'b0010011);
    assign b_type = (OP == 7'b1100011);
    assign r_type = (OP == 7'b0110011);
    
    assign instr_lui   =          (OP == 7'b0110111)                                            ;
    assign instr_auipc =          (OP == 7'b0010111)                                            ;
    assign instr_jal   =          (OP == 7'b1101111)                                            ;
    assign instr_jalr  =          (OP == 7'b1100111)                                            ;
    assign instr_beq   = b_type                      & (func3 == 3'b000)                        ;
    assign instr_bne   = b_type                      & (func3 == 3'b001)                        ;
    assign instr_blt   = b_type                      & (func3 == 3'b100)                        ;
    assign instr_bge   = b_type                      & (func3 == 3'b101)                        ;
    assign instr_bltu  = b_type                      & (func3 == 3'b110)                        ;
    assign instr_bgeu  = b_type                      & (func3 == 3'b111)                        ;
    assign instr_lb    =          (OP == 7'b0000011) & (func3 == 3'b000)                        ;
    assign instr_lh    =          (OP == 7'b0000011) & (func3 == 3'b001)                        ;
    assign instr_lw    =          (OP == 7'b0000011) & (func3 == 3'b010)                        ;
    assign instr_lbu   =          (OP == 7'b0000011) & (func3 == 3'b100)                        ;
    assign instr_lhu   =          (OP == 7'b0000011) & (func3 == 3'b101)                        ;
    assign instr_sb    = s_type                      & (func3 == 3'b000)                        ;
    assign instr_sh    = s_type                      & (func3 == 3'b001)                        ;
    assign instr_sw    = s_type                      & (func3 == 3'b010)                        ;
    assign instr_addi  =          (OP == 7'b0010011) & (func3 == 3'b000)                        ;
    assign instr_slti  =          (OP == 7'b0010011) & (func3 == 3'b010)                        ;
    assign instr_sltiu =          (OP == 7'b0010011) & (func3 == 3'b011)                        ;
    assign instr_xori  =          (OP == 7'b0010011) & (func3 == 3'b100)                        ;
    assign instr_ori   =          (OP == 7'b0010011) & (func3 == 3'b110)                        ;
    assign instr_andi  =          (OP == 7'b0010011) & (func3 == 3'b111)                        ;
    assign instr_slli  =          (OP == 7'b0010011) & (func3 == 3'b001) & (func7 == 7'b0000000);
    assign instr_srli  =          (OP == 7'b0010011) & (func3 == 3'b101) & (func7 == 7'b0000000);
    assign instr_srai  =          (OP == 7'b0010011) & (func3 == 3'b101) & (func7 == 7'b0100000);
    assign instr_add   = r_type                      & (func3 == 3'b000) & (func7 == 7'b0000000);
    assign instr_sub   = r_type                      & (func3 == 3'b000) & (func7 == 7'b0100000);
    assign instr_sll   = r_type                      & (func3 == 3'b001) & (func7 == 7'b0000000);
    assign instr_slt   = r_type                      & (func3 == 3'b010) & (func7 == 7'b0000000);
    assign instr_sltu  = r_type                      & (func3 == 3'b011) & (func7 == 7'b0000000);
    assign instr_xor   = r_type                      & (func3 == 3'b100) & (func7 == 7'b0000000);
    assign instr_srl   = r_type                      & (func3 == 3'b101) & (func7 == 7'b0000000);
    assign instr_sra   = r_type                      & (func3 == 3'b101) & (func7 == 7'b0100000);
    assign instr_or    = r_type                      & (func3 == 3'b110) & (func7 == 7'b0000000);
    assign instr_and   = r_type                      & (func3 == 3'b111) & (func7 == 7'b0000000);
    
    assign ExtOp =  {u_type,
                     j_type,
                     s_type,
                     i_type,
                     b_type
                    };
    
    assign ALUAsrc = {  j_type |  instr_auipc,       // pc
                       ~j_type & ~instr_auipc       // rs1_value
                      };
    assign ALUBsrc = {   u_type | s_type | i_type,  // imm
                         j_type,                    // 4
                         b_type | r_type            // rs2_value
                      };
    
    assign ALUctr[ 0] = instr_lui                                         ;
    assign ALUctr[ 1] = instr_lb   | instr_lh    | instr_lw    | instr_lbu 
                      | instr_lhu  | instr_sb    | instr_sh    | instr_sw 
                      | instr_addi | instr_add   | instr_auipc | j_type   ;
    assign ALUctr[ 2] = instr_sub                | b_type                 ;
    assign ALUctr[ 3] = instr_slt  | instr_slti                           ;
    assign ALUctr[ 4] = instr_sltu | instr_sltiu                          ;
    assign ALUctr[ 5] = instr_xori | instr_xor                            ;
    assign ALUctr[ 6] = instr_ori  | instr_or                             ;
    assign ALUctr[ 7] = instr_and  | instr_andi                           ;
    assign ALUctr[ 8] = instr_slli | instr_sll                            ;
    assign ALUctr[ 9] = instr_srli | instr_srl                            ;
    assign ALUctr[10] = instr_srai | instr_sra                            ;
    
    
    assign RegWr    = ~(instr_sw  | instr_sh   | instr_sb) & ~b_type;
    assign MemtoReg =   instr_lb  | instr_lh   | instr_lw | instr_lbu | instr_lhu;
    assign MemWr    =   s_type;
    assign Branch   = { instr_bgeu, instr_bltu , instr_bge, instr_blt , instr_bne, instr_beq};
    assign Jump     = { instr_jalr, instr_jal};
    assign Load     = { instr_lhu , instr_lbu  , instr_lw , instr_lh  , instr_lb};
    assign Store    = { instr_sw  , instr_sh   , instr_sb};
    
    assign shamt    =  instr_slli | instr_srli | instr_srai;
    
endmodule

