//This control unit is not built for RISC-V
//you will need to make substantial edits for it to work 

module MIPS_control_unit (ALUOp,
                          ALUSrcA,
                          ALUSrcB,
                          MemtoReg,
                          RegDst,
                          RegWrite, 
                          MemRead,
                          MemWrite,
                          IorD,
                          IRWrite, 
                          PCWrite,
                          PCWriteCond,
                          PCSource,
                          Opcode,
                          CLK,
                          Reset
                          );

   output [1:0] ALUOp;
   output [1:0] PCSource;
   output [1:0] ALUSrcB;
   output       ALUSrcA;
   output       MemtoReg;
   output       RegDst;
   output       RegWrite;
   output       MemRead;
   output       MemWrite;
   output       IorD;
   output       IRWrite;
   output       PCWrite;
   output       PCWriteCond;

   //-- You can add these state registers to the IO pins in the module
   //-- declaration and uncomment the output statements here if you want, but
   //-- Quartus won't identify this as a State Machine with the state
   //-- registers as inputs or outputs.
   //output [3:0] current_state;
   //output [3:0] next_state;

   input [5:0]  Opcode;
   input        CLK;
   input        Reset;

   reg [1:0]    ALUOp;
   reg [1:0]    PCSource;
   reg [1:0]    ALUSrcB;
   reg          ALUSrcA;
   reg          MemtoReg;
   reg          RegDst;
   reg          RegWrite;
   reg          MemRead;
   reg          MemWrite;
   reg          IorD;
   reg          IRWrite;
   reg          PCWrite;
   reg          PCWriteCond;

   //state flip-flops
   reg [3:0]    current_state;
   reg [3:0]    next_state;

   //state definitions
   parameter    Fetch = 0;
   parameter    Decode = 1;
   parameter    Mem1 = 2;
   parameter    LW1 = 3;
   parameter    LW2 = 4;
   parameter    SW1 = 5;
   parameter    R_Execution = 6;
   parameter    R_Write = 7;
   parameter    Branch = 8;
   parameter    Jump = 9;

   //register calculation
   always @ (posedge CLK, posedge Reset)
     begin
        if (Reset)
          current_state = Fetch;
        else 
          current_state = next_state;
     end


   //OUTPUT signals for each state (depends on current state)
   always @ (current_state)
     begin
        //Reset all signals that cannot be don't cares
        RegWrite = 0; 
        MemRead = 0;
        MemWrite = 0; 
        IRWrite = 0; 
        PCWrite = 0;
        PCWriteCond = 0;
        
        case (current_state)
          
          Fetch:
            begin
               MemRead = 1;
               ALUSrcA = 0;
               IorD = 0;
               IRWrite =  1;
               ALUSrcB = 1;
               ALUOp = 0;
               PCWrite = 1;
               PCSource = 0;
            end 
                         
          Decode:
            begin
               ALUSrcA = 0;
               ALUSrcB = 3;
               ALUOp = 0;
            end
        
          R_Execution:
            begin
               ALUSrcA = 1;
               ALUSrcB = 0;
               ALUOp = 2;
            end
        
          R_Write:
            begin
               RegDst = 1;
               RegWrite = 1;
               MemtoReg = 0;
            end
        
          Branch:
            begin
               ALUSrcA = 1;
               ALUSrcB = 0;
               ALUOp = 1;
               PCWriteCond = 1;
               PCSource = 1;
            end
        
          Jump:
            begin
               PCWrite = 1;
               PCSource = 2;
            end
          
          Mem1:
            begin
               $display ("Mem1 outputs not implemented"); 
            end
        
        
          default:
            begin $display ("not implemented"); end
          
        endcase
     end
                
   //NEXT STATE calculation (depends on current state and opcode)       
   always @ (current_state, next_state, Opcode)
     begin         

        $display("The current state is %d", current_state);
        
        case (current_state)
          
          Fetch:
            begin
               next_state = Decode;
               $display("In Fetch, the next_state is %d", next_state);
            end
          
          Decode: 
            begin       
               $display("The opcode is %d", Opcode);
               case (Opcode)
                 0:
                   begin
                      next_state = R_Execution;
                      $display("The next state is R");
                   end
                 2:
                   begin
                      next_state = Jump;
                      $display("The next state is Jump");
                   end
                 4:
                   begin
                      next_state = Branch;
                      $display("The next state is Branch");
                   end
                 35:
                   begin
                      next_state = Mem1;
                      $display("The next state is Mem");
                   end
                 43:
                   begin next_state = Mem1;
                      $display("The next state is Mem");
                   end
                 default:
                   begin 
                      $display(" Wrong Opcode %d ", Opcode);  
                      next_state = Fetch; 
                   end
               endcase  
               
               $display("In Decode, the next_state is %d", next_state);
            end
          
          R_Execution:
            begin
               next_state = R_Write;
               $display("In R_Exec, the next_state is %d", next_state);
            end
          
          R_Write:
            begin
               next_state = Fetch;
               $display("In R_Write, the next_state is %d", next_state);
            end
          
          Branch:
            begin
               next_state = Fetch;
               $display("In Branch, the next_state is %d", next_state);
            end

          Mem1:
            begin
               //not implemented - forcing return to cycle 1
               next_state = Fetch;
               $display("In Mem1, the next_state is %d", next_state);
            end
          
          Jump:
            begin
               next_state = Fetch;
               $display("In Jump, the next_state is %d", next_state);
            end
          
          default:
            begin
               $display(" Not implemented!");
               next_state = Fetch;
            end
          
        endcase
        
        $display("After the tests, the next_state is %d", next_state);
                
     end

endmodule