`timescale 1ns / 1ps



module EMModule(
    input wire reset, clk,
    input wire [50:0] PipIn,
    output wire [61:0] PipOut
    );
    
    wire [8:0] instr, op1, op0, FUAddr,FUJB,PCout,JBRes,FUJ,FUB,AddiOut,AluOut,RFIn,dataMemOut,SE1N,SE2N,SE3N,bankOP,jumpNeg;
    wire [3:0] aluOp;
    wire [2:0] FU;
    wire [1:0] bankS;
    wire addiS, RegEn, loadS, fetchBranch, cout0, cout1, link, js, dataMemEn;
    
    assign instr = PipIn[50:42];
    assign op0 = PipIn[41:33];
    assign op1 = PipIn[32:24];
    assign PCout = PipIn[23:15];
    assign addiS = PipIn[14];
    assign RegEn = PipIn[13];
    assign loadS = PipIn[12];
    assign link = PipIn[11];
    assign js = PipIn[10];
    assign dataMemEn = PipIn[9];
    assign aluOp = PipIn[8:5];
    assign FU = PipIn[4:2];
    assign bankS = PipIn[1:0];
    
    assign PipOut = {RegEn,PCout,bankOP,FUAddr,AluOut,dataMemOut,AddiOut,instr[4:3],bankS[0],loadS,link,addiS,fetchBranch};   // concat all signals into one
    
    dataMemory dM(
        .clk(clk),
        .writeEnable(dataMemEn),
        .writeData(op0),
        .address(op1),
        .readData(dataMemOut)
    );
    
    RegFile Bank(
        .clk(clk),
        .reset(reset),
        .write_index(instr[2:1]),
        .op0_idx(instr[2:1]),
        .op1_idx(2'b00),//Doesn't matter
        .write_data(op0),
        .op0(bankOP),
        .op1(),
        .En(bankS[1])
    );
    
    ALU alu(
        .opcode(aluOp),
        .operand0(op0),
        .operand1(op1),
        .result(AluOut)     
    );
    
        add_9bit JBAdder(
        .A(PCout),
        .B(JBRes),
        .Cin(1'b0),
        .Sum(FUJB),
        .Cout(cout0)
    );

    mux_2_1 mux0(
        .A(op0),
        .B(FUJB),
        .out(FUAddr),
        .switch(FU[1])
    );

    twos_compliment_9bit two_comp0(
        .A({4'b0000,instr[4:0]}),
        .B(jumpNeg)
    );

    mux_2_1 mux1(
        .A({4'b0000,instr[4:0]}),
        .B(jumpNeg),
        .out(SE2N),
        .switch(js)
    );

    mux_2_1 mux2(
        .A(SE2N), //Jump -- Change with signer module!
        .B(SE1N),//Branch -- Change with signer module!
        .out(JBRes),
        .switch(FU[2])
    );

    sign_extend_3bit SE1(
        .A(instr[2:0]),
        .B(SE1N)
    );

    bit1_mux_2_1 BranMux( // BEQ MUX
        .A(FU[0]),
        .B(AluOut[0]),
        .out(fetchBranch),
        .switch(FU[2]) // FU[2] only goes high when BEQ
    );

    ///--------------------------Addi Stuff

    add_9bit Addier(
        .A(SE3N), // Change with signer module!
        .B(op0),
        .Cin(1'b0),
        .Sum(AddiOut),
        .Cout(cout1)
    );

    sign_extend_3bit SE3(
        .A(instr[2:0]),
        .B(SE3N)
    );
endmodule
