`timescale 1ns / 1ps

module CPU9bits(
    input wire reset, clk,
    output wire [8:0] result,
    output wire done
        );
    
    wire [8:0] RFIn,FUAddr, op0_ext, op1_ext, wr_ext, op0_sub, op1_sub, op0_zero, op1_zero, op0_and, op1_and, newOp0, newOp1;
    wire [1:0] instr, op0_idx, op1_idx;
    wire fetchBranch, RegEn, compare0, compare1;
    wire [50:0] FDOut, FDPipOut, EMIn;
    wire [61:0] EMOut, EMPipOut;
    
    
    assign result = RFIn;
    assign EMIn = {FDPipOut[50:42], newOp0, newOp1, FDPipOut[23:0]};

    
    FDModule FD(
        .reset(reset),
        .clk(clk),
        .FUIdx(fetchBranch),
        .En(RegEn),
        .RFIn(RFIn),
        .AddrIn(FUAddr), 
        .RFIdx(instr),
        .result(FDOut),
        .done(done),
        .compare0(compare0),
        .compare1(compare1),
        .op0_idx(op0_idx),
        .op1_idx(op1_idx)
     );
     
     fDPipReg pipe1(
        .clk(clk), 
	    .reset(reset), 
	    .En(1'b0), 
	    .Din(FDOut), 
	    .Dout(FDPipOut)
	 );
        
     EMModule EM(
        .reset(reset),
        .clk(clk),
        .PipIn(EMIn),
        .PipOut(EMOut)
     );
    
    eMPipReg pipe2(  
        .clk(clk), 
	    .reset(reset), 
	    .En(1'b0), 
	    .Din(EMOut), 
	    .Dout(EMPipOut)
	 );
    
     WMUdule W(
        .PipIn(EMPipOut),
        .RFIn(RFIn),
        .FUAddr(FUAddr),
        .instr(instr),
        .fetchBranch(fetchBranch), 
        .RegEn(RegEn)
     );
     
     sign_extend_2bit ext0(
     .A(op0_idx),
     .B(op0_ext)
     );
     
     sign_extend_2bit ext1(
     .A(op1_idx),
     .B(op1_ext)
     );
     
     sign_extend_2bit ext2(
     .A(instr),
     .B(wr_ext)
     );
     
     sub_9bit sub0(
     .A(op0_ext),
     .B(wr_ext),
     .C(op0_sub)
     );
     
     sub_9bit sub1(
     .A(op1_ext),
     .B(wr_ext),
     .C(op1_sub)
     );
     
     BEQ beq0(
     .A(op0_sub),
     .B(op0_zero)
     );
     
     BEQ beq1(
     .A(op1_sub),
     .B(op1_zero)
     );
     
     and_9bit and0(
     .A(~op0_zero),
     .B({8'b00000000,compare0}),
     .C(op0_and)
     );
     
     and_9bit and1(
     .A(~op1_zero),
     .B({8'b00000000,compare1}),
     .C(op1_and)
     );
     
     mux_2_1 mux0(
     .switch(op0_and[0]),
     .A(FDOut[41:33]),
     .B(EMPipOut[33:25]), //ALUOut
     .out(newOp0)
     );
     
     mux_2_1 mux1(
     .switch(op1_and[0]),
     .A(FDOut[32:24]),
     .B(EMPipOut[33:25]), //ALUOut
     .out(newOp1)
     );
     

endmodule

module CPU9bits_tb();
    reg clk, reset;
    wire done;
    wire [8:0] result;

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

    CPU9bits CPU9bits0(
        .reset(reset),
        .clk(clk),
        .done(done),
        .result(result));

    initial begin
    	#5
    	reset = 1'b1;
    	#10
    	reset = 1'b0;
    	#300
        $finish;
        
    end
endmodule
