/// LSU EE 7700-3 - Advanced Computer Implementation
//
// Decode-and-Dispatch Simulator Code Outline
//
// Time-stamp: <11 February 2005, 15:24:01 CST, koppel@nested>

// Outline of code for a simple decode-and-dispatch instruction set
// simulator.  Just an outline, probably won't compile.

enum Opcode
  {
    Op_NOP = 0,
    Op_ADD,
    Op_SUB
};

void
main_loop_as_shown_in_class() // With comments added.
{

  int pc;
  int regs[32];
  int ready[32];
  int t = 0;

  while( true )
    {
      int insn = read_word(pc);         // Read instruction from memory.
      int nnpc = pc + 4;                // Provisionally set next-next address.
      Opcode op = extract_opcode(insn); // Extract opcode from instruction.

      switch( op ) {

      case OP_ADD:

        // Advance time to when all operands will be ready.
        //
        t = max(t, ready[get_rs(insn)], ready[get_rt(insn)] );

        // Perform operation.
        //
        regs[ get_rd(insn) ] = regs[ get_rs(insn) ] + regs[ get_rt(insn) ];

        // Set time that result will be ready.
        //
        ready[ get_rd(insn) ] = t + 1;

        // Set time that next instruction will be processed.
        //
        t += 1;
        break;

      case OP_SUB:
        t = max(t, ready[get_rs(insn)], ready[get_rt(insn)] );
        regs[ get_rd(insn) ] = regs[ get_rs(insn) ] - regs[ get_rt(insn) ];
        ready[ get_rd(insn) ] = t + 1;
        t += 1;
        break;

      case OP_BEQ:
        t = max(t, ready[get_rs(insn)], ready[get_rt(insn)] );
        if( regs[ get_rs(insn) ] == regs[ get_rt(insn) ] )
          nnpc = pc + ( get_immed(insn) << 2 );
        t += 2;
        break;

      default:
        fprintf(stderr,"We're sorry, your simulation can't run as submitted.\n"
                "Please check the code and try again later.\n");
        exit(1);
      }

      pc = npc;
      npc = nnpc;
    }
}


void
main_loop_with_after_class_simplifications()
{

  int pc;
  int regs[32];
  int ready_time[32];
  int t = 0;

  while( true )
    {
      const int insn = read_word(pc);
      int nnpc = pc + 4;
      const Opcode op = extract_opcode(insn);

      const int rd = get_rd(insn);
      const int rs = get_rs(insn);
      const int rt = get_rt(insn);
      const int immed = get_immed(insn);
      int& rdval = regs[ rd ];
      int& rsval = regs[ rs ];
      int& rtval = regs[ rt ];
      const int rstime = ready_time[ rs ];
      const int rttime = ready_time[ rt ];
      int& rdtime = ready_time[ rd ];

      switch( op ) {

      case OP_ADD:
        t = max3(t, rstime, rttime);
        rdval = rsval + rtval;
        rdtime = t + 1;
        t += 1;
        break;

      case OP_SUB:
        t = max3(t, rstime, rttime);
        rdval = rsval - rtval;
        rdtime = t + 1;
        t += 1;
        break;

      case OP_BEQ:
        t = max3(t, rstime, rttime);
        if( rsval == rtval )
          nnpc = pc + ( immed << 2 );
        t += 2;
        break;

      default:
        fprintf(stderr,"We're sorry, your simulation can't run as submitted.\n"
                "Please check the code and try again later.\n");
        exit(1);
      }

      pc = npc;
      npc = nnpc;
    }
}