/*

Freely Distributable C30 Simulator Package

Copyright (c) 1996-1998 The University of Texas
All Rights Reserved.

This program is free software; you can redistribute it and/or modify 
it under the terms of the GNU General Public License as published by 
the Free Software Foundation; either version 2 of the License, or 
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

The GNU Public License is available in the file LICENSE, or you
can write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA, or you can find it on the
World Wide Web at http://www.fsf.org.

Authors: Chi Duong, Brian Evans, and Chris Moy
Version: @(#)fetch.cc	1.22	01/19/98

Department of Electrical and Computer Engineering
The University of Texas, Austin, TX 78712-1084

*/

#include <stdio.h>

#include "pipeline.h"
#include "state.h"
#include "memmap.h"

/*
Model the fetch stage of the pipeline. It loads the instruction
register from simulated memory. It determines the next program
counter value for loop modes. If the simulator is not in loop
mode, the routine checks for an instruction PC update (branches,
calls) and loads the PC accordingly. If none of these conditions
exist, the PC is just incremented.
*/
void C30SimFetch(state* st, pipeline* pipe) {
  st->pc = pipe->pci[0];
  pipe->inst = *C30SimMemMap(st, pipe->pc);     /* fetch next instruction */
  pipe->pci[0] = pipe->pci[1];
  pipe->pci[1] = pipe->pc;

  /* check for repeat mode and end of repeat block */
  if ((st->st & C30_CONDFLAG_REPEAT_MODE) && (pipe->pc == st->re)) {
    if ((int32)(--pipe->rc) == -1) {                         /* decrement the repeat counter */
      st->st &= ~C30_CONDFLAG_REPEAT_MODE;          /* clear repeat mode bit */
      pipe->pc++;
    }
    else
      pipe->pc = st->rs;                /* reset the PC to beginning of loop */
  }

  else if (pipe->modifyPC){
    pipe->pc = pipe->newPC;
    pipe->modifyPC = 0;
  }
  else
    pipe->pc++;                         /* no special cases, just increment */
}

/*
Model the operand read stage of the pipeline. It fetches
operands from pointers, converts to separate floating point
operands, and passes on variables to the execute stage that
are not used in the read stage.
*/
void C30SimRead(pipeline* pipe, state* st) {
  uint32* lowerRegPtr = &st->Sregs[__r0];
  uint32* upperRegPtr = &st->Sregs[__r7];
  uint32* src;

  if ((src = pipe->source1)) {
    pipe->oprnd1 = pipe->opfloat1 = *src;                  /* operand fetch */
    if ((src >= lowerRegPtr) && (src <= upperRegPtr)) {
      /* the operand only needs to be adjusted if the operand is in
         an R register, in which case the rx value is placed in the upper
         8 bits and everything else is shifted right */
      pipe->opexp1 = *C30_EXPONENT_REGISTER_PTR(src);
    }
    else {
      pipe->opexp1 = (pipe->opfloat1 & 0xff000000L);
      pipe->opfloat1 <<= 8;
    }
  } 

  if ((src = pipe->source2)) {
    pipe->oprnd2 = pipe->opfloat2 = *src;
    if ((src >= lowerRegPtr) && (src <= upperRegPtr)) {
      pipe->opexp2 = *C30_EXPONENT_REGISTER_PTR(src);
    }
    else {
      pipe->opexp2 = (pipe->opfloat2 & 0xff000000L);
      pipe->opfloat2 <<= 8;
    }
  }

  if ((src = pipe->source3)) {
    pipe->oprnd3 = pipe->opfloat3 = *src;
    if ((src >= lowerRegPtr) && (src <= upperRegPtr)) {
      pipe->opexp3 = *C30_EXPONENT_REGISTER_PTR(src);
    }
    else {
      pipe->opexp3 = (pipe->opfloat3 & 0xff000000L);
      pipe->opfloat3 <<= 8;
    }
  }

  if ((src = pipe->source4)) {
    pipe->oprnd4 = pipe->opfloat4 = *src;
    if ((src >= lowerRegPtr) && (src <= upperRegPtr)) {
      pipe->opexp4 = *C30_EXPONENT_REGISTER_PTR(src);
    }
    else {
      pipe->opexp4 = (pipe->opfloat4 & 0xff000000L);
      pipe->opfloat4 <<= 8;
    }
  }

  /* pass on the variables to the execute stage */
  pipe->finalOpcode1 = pipe->opcode1;
  pipe->finalDest1 = pipe->dest1;
  pipe->finalDest2 = pipe->dest2;
}
