`timescale 1ns / 1ps

module RegFile(input wire clk, reset,En,
                input wire [1:0] write_index, op0_idx, op1_idx,
                input wire [8:0] write_data,
                output wire [8:0] op0, op1);
    
    wire [3:0] decOut;
    wire [8:0] r0_out, r1_out, r2_out, r3_out;
    
    // To select a register En input must be 2'b00
    
    decoder d0(
        .index(write_index),
        .regOut(decOut),
        .En(En)
    );
    
    
    register r0(
        .clk(clk),
        .reset(reset),
        .En(decOut[0]),
        .Din(write_data),
        .Dout(r0_out));
        
    register r1(
        .clk(clk),
        .reset(reset),
        .En(decOut[1]),
        .Din(write_data),
        .Dout(r1_out));
        
    register r2(
        .clk(clk),
        .reset(reset),
        .En(decOut[2]),
        .Din(write_data),
        .Dout(r2_out));
        
    register r3(
        .clk(clk),
        .reset(reset),
        .En(decOut[3]),
        .Din(write_data),
        .Dout(r3_out));    
        
    mux_4_1 m0(
        .A(r0_out),
        .B(r1_out),
        .C(r2_out),
        .D(r3_out),
        .out(op0),
        .switch(op0_idx));
        
    mux_4_1 m1(
        .A(r0_out),
        .B(r1_out),
        .C(r2_out),
        .D(r3_out),
        .out(op1),
        .switch(op1_idx));
    
endmodule

//testbench
module regFile_tb();
    reg [8:0] write_d;
    reg [1:0] w_idx, op0_idx, op1_idx;
    reg reset,clk;
    wire [8:0] op0,op1;

    initial begin
        clk = 1'b0;
    end
    always begin
        #5 clk = ~clk; // Period to be determined
    end

    RegFile regFile0(
        .clk(clk),
        .reset(reset),
        .write_index(w_idx),
        .op0_idx(op0_idx),
        .op1_idx(op1_idx),
        .write_data(write_d),
        .op0(op0),
        .op1(op1));
    
    initial begin
        reset = 0;
        #5
        reset = 1;
        #5
        reset = 0;
        w_idx = 2'b00;
        op0_idx = 2'b00;
        op1_idx = 2'b00;
        write_d = 9'b000000011;
        #5
        w_idx = 2'b01;
        #5
        w_idx = 2'b10;
        #5
        w_idx = 2'b11;
        #5
        reset = 0;
        w_idx = 2'b00;
        op0_idx = 2'b10;
        op1_idx = 2'b11;
        write_d = 9'b001111000;
        #5
        reset = 0;
        w_idx = 2'b01;
        op0_idx = 2'b00;
        op1_idx = 2'b01;
        write_d = 9'b000001111;
        #5
        reset = 0;
        w_idx = 2'b10;
        op0_idx = 2'b00;
        op1_idx = 2'b10;
        write_d = 9'b111000001;
        #5
        reset = 0;
        w_idx = 2'b11;
        op0_idx = 2'b11;
        op1_idx = 2'b10;
        write_d = 9'b100110001;
        #5
        reset = 1;
        w_idx = 2'b00;
        #5
        w_idx = 2'b10;
        #5
        w_idx = 2'b01;
        #5
        w_idx = 2'b11;
        #5
        $finish;

    end
endmodule