/// EE 3755 -- Fall 2012 -- Computer Organization
//
/// Example used in class 7 November 2012.

/// MIPS Processor Functional Simulator,  Day 1
//
//  Will be added to each day.
//


`define MIPS_PROG "tfirst.v"

module proc(exc,clk);
   input clk;
   output exc;

   // add $2, $3, $4

   reg [7:0]  mem ['h400000:'h400200];

   reg [31:0]  gpr[0:31];
   reg [31:0]  pc, npc, simmed, uimmed;
   reg [15:0]  immed16;
   reg [31:0]  instruction_register;

   reg [4:0]   rs, rt, rd;

   parameter   O_type_r = 0;
   parameter   O_ADDI = 0x8;

   parameter   F_ADD = 0x20;
   parameter   F_SUB = 0x22;

   initial begin pc = 'h400000; npc = pc + 4; end

   always @ ( posedge clk )
     begin

        instruction_register = { mem[pc], mem[pc+1], mem[pc+2], mem[pc+3] };
        
        opcode = instruction_register[31:26];
        rs = instruction_register[25:21];
        rt = instruction_register[20:16];
        rd = instruction_register[15:11];
        func = instruction_register[5:0];
        immed16 = instruction_register[15:0];
        simmed = { immed16[15] ? 16'hffff : 16'h0, immed16 };
        uimmed = { 16'h0, immed16 };

        pc = npc;
        nnpc = pc + 4;
        gpr[0] = 32'h0;

        rs_val = rs ? gpr[rs] : 32'h0;
        rt_val = rt ? gpr[rt] : 32'h0;
        
        case ( opcode )
          O_ADDI:  gpr[rt] = rs_val + simmed;
          O_ANDI:  gpr[rt] = gpr[rs] & uimmed;
          O_LBU: gpr[rt] = { 24'h0, mem[ gpr[rs] + simmed ] };
          O_LHU: gpr[rt] = { 16'h0, 
                             mem[ gpr[rs] + simmed ],
                             mem[ gpr[rs] + simmed +1 ] };
          
          O_BEQ: if ( gpr[rs] == gpr[rt] ) nnpc = pc + simmed * 4;

          O_type_r:
            case ( func )
              F_ADD:  gpr[rd] = gpr[rs] + gpr[rt];
              F_SUB:  gpr[rd] = gpr[rs] - gpr[rt];
              F_JR: nnpc = rs_val;
              F_JALR: 
                nnpc = rs_val;
              gpr[rd] = npc + 4;

            endcase

        endcase

        npc = nnpc;

     end

endmodule

`include "mips_fs_tb.v"