epsilon.h 9.73 KB
/*
 * Copyright (C) 1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * Copyright (C) 1998 Digital Equipment Corporation
 *
 * This file is part of the SimOS distribution.
 * See LICENSE file for terms of the license.
 *
 */

/*
 *
 */

/* Epsilon CPU Scheduler Interface definition */

#ifndef EPSILON_H
#define EPSILON_H

#define EPSILON_USE_MEMREF

typedef int Instid;
typedef long Inum;
#define N_INFLIGHT_INSTRS 64
#define inumInstid(inum) ((inum)&(N_INFLIGHT_INSTRS-1))
#define NEXT_INSTID(n) (((n)+1)&(N_INFLIGHT_INSTRS-1))
#define PREV_INSTID(n) (((n)-1)&(N_INFLIGHT_INSTRS-1))

#define N_LOGICAL_REGISTERS 80 /* 32 integer, 32 float, 16 shadow */
#define N_PHYSICAL_REGS 512
#define ZERO_REGISTER_DEST_PHYSREG (ZERO_REGISTER+32)
typedef short regname_t;


typedef struct InflightInstructionState_s {
  VA PC;
  union alpha_instruction instr;
  unsigned isMemop : 1;
  Reg64 fpcr;
  Inum inum;       /* fetchnum, unique for a given CPU */
  /* for tracking instruction state */
  unsigned inflight : 1;
  unsigned fetched : 1;
  unsigned issued : 1;
  unsigned committed : 1;

  unsigned trapfree : 1; /* set this to one when this instruction can no longer cause a trap */
  unsigned untrappable : 1; /* set this to one when we're not allowed to trap an instruction 
                             * (e.g. after we issue an uncached memop request) */

  unsigned trapped : 1;
  unsigned memopRequested : 1;
  unsigned memopReadyToComplete : 1;
  unsigned memopCompleted : 1;
  unsigned done : 1;                         /* ((committed && (!isMemop || memopCompleted)) || trapped) */
  unsigned readyToIssue : 1;
  unsigned readyToRetire : 1;

  Inum inorderNext;
  Inum inorderPrev;

  ulong runstate;
  short  immuStatus;
  short  dmmuStatus;
  short  memrefStatus; /* result from cache request */
  /* for recovering instruction map on traps */
  regname_t pra; /* physical ra number */
  regname_t prb; /* physical ra number */
  regname_t prc; /* physical ra number */
  regname_t prdest; /* physical destreg number */
  regname_t oldprdest; /* old physical destreg number */
  regname_t lrdest; /* logical destreg number */
  /* for loads and stores: store-buffer */
  VA     eaddr;
  PA     paddr;
  MA     maddr;
  struct StoreBuffer {
    Reg64  vmask;
  } storebuffer;
  Reg64  value; /* for stores only */
  Inum lastStoreInum;
  /* for tracking control flow */
  VA     nextpc;

  /* for speculative exception handling (virtualizing IPR_EXC_ADDR) */
  AlphaTrapState *trapState;
} InflightInstructionState;

/* 
 * EpsilonState:
 *   
 *   Initial regmap maps each logical register to the physical register of
 *   the same number, except that both ZERO_REGISTER and FP_ZERO_REGISTER
 *   map to ZERO_REGISTER.  Physical register number FP_ZERO_REGISTER is
 *   used to catch the discarded value from instructions whose logical
 *   destination register is either ZERO_REGISTER or FP_ZERO_REGISTER.
 *   
 *   The physical register free list is linked through the register file,
 *   with the last register containing -1.
 *   
 */
typedef  enum { 
  EpsilonTTExitSimulator, 
  EpsilonTTRegisterChangedExternally, 
  EpsilonTTInterrupt, 
  EpsilonTTIMMUException, 
  EpsilonTTIllegalOpcode,
  EpsilonTTFEN,
  EpsilonTTArith,
  EpsilonTTDMMUHWReadException, 
  EpsilonTTDMMUReadException, 
  EpsilonTTDMMUWriteException,
  /* these abort later instructions */
  EpsilonTTMemTrap,
  EpsilonTTMispredict,
  EpsilonTTPalCall,
  EpsilonTTHwRei,
  EpsilonTTNumTypes
} EpsilonTrapType;

typedef struct EpsilonState {
  VA nextpc;
  Inum stallFetchUntilInum; /* inclusive */
  Inum lastInumFetched;
  Inum lastInumMapped;
  Inum lastInumCommitted;
  Inum lastInumDone;
  Inum lastInumUntrapped;
  Inum nextInum;
  Inum lastStoreInum;
  Inum trapPointInum; /* points to lowest inum that may still be trapped */
  long fetchCount;
  regname_t regmap[N_LOGICAL_REGISTERS];			/* fetch-time regmap */
  regname_t committedRegmap[N_LOGICAL_REGISTERS];		/* committed regmap */
  regname_t freereg;
  int useShadowRegisters;
  int myNum;
  Reg regs[N_PHYSICAL_REGS];
  int regValid[(N_PHYSICAL_REGS+31)/32];
  int regAllocated[(N_PHYSICAL_REGS+31)/32];
  InflightInstructionState iqueue[N_INFLIGHT_INSTRS];
  /* committed trap state */
  AlphaTrapState *oldestTrapState;
  /* speculative trap state */
  AlphaTrapState *newestTrapState;

  /* trap handling */
  int trapPending;
  VA trapPC; /* PC of trapped instruction */
  EpsilonTrapType trapType;
  Inum trapCauseInum; /* inum of cause of trap */
  Inum trapAbortInum; /* first inum to kill */
  /* interrupt handling */
  long pending_irq;

  /* ldst */
  int pendingMemops;
  Inum stalledMemop;
} EpsilonState;

extern EpsilonState *epeArray;
extern EpsilonState **EPE;

#define EpsilonInstructionIsMemop(cpu,instid) EPE[cpu]->iqueue[instid].isMemop
#ifdef op_stb
#define ALPHA_STORE_OPCODES_MASK \
   ((1L<<op_stw)|(1L<<op_stb)|(1L<<op_stq_u)|(1L<<op_stf)|(1L<<op_stg)|(1L<<op_sts)|(1L<<op_stt)|(1L<<op_stl)|(1L<<op_stq)|(1L<<op_stl_c)|(1L<<op_stq_c)|(1L<<PRIV_OP_HW_ST))
#else
#define ALPHA_STORE_OPCODES_MASK \
   ((1L<<op_stq_u)|(1L<<op_stf)|(1L<<op_stg)|(1L<<op_sts)|(1L<<op_stt)|(1L<<op_stl)|(1L<<op_stq)|(1L<<op_stl_c)|(1L<<op_stq_c)|(1L<<PRIV_OP_HW_ST))
#endif
#define ALPHA_LOAD_OPCODES_MASK \
   ((1L<<op_ldwu)|(1L<<op_ldbu)|(1L<<op_ldq_u)|(1L<<op_ldf)|(1L<<op_ldg)|(1L<<op_lds)|(1L<<op_ldt)|(1L<<op_ldl)|(1L<<op_ldq)|(1L<<op_ldl_l)|(1L<<op_ldq_l)|(1L<<PRIV_OP_HW_LD))

#define EpsilonInstructionIsStore(cpu,instid) \
   ((ALPHA_STORE_OPCODES_MASK >> EPE[cpu]->iqueue[instid].instr.common.opcode)&1)
#define EpsilonInstructionIsLoad(cpu,instid) \
   ((ALPHA_LOAD_OPCODES_MASK >> EPE[cpu]->iqueue[instid].instr.common.opcode)&1)

#define EpsilonInstructionNextPC(cpu,instid) EPE[cpu]->iqueue[instid].nextpc

#define EpsilonPhysicalRegisterIsValid(epe,physreg) \
    ((epe->regValid[physreg>>5]>>(physreg&0x1f))&1)
#define EpsilonPhysicalRegisterSetValid(epe,physreg) \
     (epe->regValid[physreg>>5] |= (1 << (physreg&0x1f)))
#define EpsilonPhysicalRegisterClearValid(epe,physreg) \
     (epe->regValid[physreg>>5] &= ~(long)(1L << (physreg&0x1f)))

#define EpsilonPhysicalRegisterIsAllocated(epe,physreg) \
    ((epe->regAllocated[physreg>>5]>>(physreg&0x1f))&1)
#define EpsilonPhysicalRegisterSetAllocated(epe,physreg) \
     (epe->regAllocated[physreg>>5] |= (1 << (physreg&0x1f)))
#define EpsilonPhysicalRegisterClearAllocated(epe,physreg) \
     (epe->regAllocated[physreg>>5] &= ~(long)(1L << (physreg&0x1f)))

typedef struct EpsilonParams {
  int padding;
  int debugScheduler;
  int debugTrapMask;
  int debugSchedulerDuringInterrupt;
  int usePmintCPUCycle;
  int checkRegmap;
  int trapClearRegisterLocks;
  int trapNoStall;
  int trapNotifyInterrupts;
  int interruptTrapUncommitted;
  int width;
  int pipelined;
  int interruptFrequencyMask;
  int newTrapStates;
  int takeInterruptAtRei;
  int useMemRef;
  int fetchAheadLimit;
} EpsilonParams;

/* Interface functions  */

/* Called at initialization time.
 * Passes to the PM the following:
 *
 * -- Maximum number of threads
 * -- Execution flags (trace option etc.)
 * -- Number of initial ready contexts (threads)
 */
void pmint_init(int max_nthreads, int cur_nthreads);

/* Indicates to PM that a new thread has begun, along with which
 * instruction stream it will execute
 */
void pmint_thread_begin(int cpu);

/* Indicates to PM that the thread has died, and will not produce any
 * more instructions
 */
void pmint_thread_end(int cpu);

/* Indicates to PM that the thread will not produce any more instructions
 * until it is unblocked
 */
void pmint_thread_block(int cpu);

/* Indicates that the thread is ready to resume execution */
void pmint_thread_unblock(int cpu);

void pmint_quiesce_thread(int cpu, void *picode, unsigned long addr);

/* simulation control */
void pmint_request_begin_skipping (long how_many_to_skip);
void pmint_request_end_skipping ();
void pmint_request_end_simulation ();

void pmint_record_event (int cpu, long event, long value);

/* pass control to pmint, which will schedule instructions */
void pmint_execute();

/* give PMINT a chance to clean up */
void pmint_done();

/* Called to get current simulation cycle */
unsigned long pmint_get_sim_cycle();



/* interface functions provided for EPSILON */

/*** FETCH ***/

/* returns instid */
Inum EpsilonFetchInstruction(int cpu, VA predicted_pc);
/* Causes GAMMA to fetch the next instruction from thread 'tid' at address
 * predicted_pc.  GAMMA will call the appropriate EVSIM_queue... procedure
 * to enqueue the instruction.  * Otherwise returns the unique id of the
 * dynamic instance of the fetched instruction.  */

/*** ISSUE and EXECUTE ***/

void EpsilonIssueInstruction(int cpu, Inum inum); 
/* Computes and returns the virtual address being accessed.
 *
 */

void EpsilonRequestMemop(int cpu, Inum inum); 
/* for a load instruction, reads store-buffer or memory and delivers data to target register,
 * for a write instruction, flushes value from store-buffer to memory 
 */

void EpsilonCompleteMemop(int cpu, Inum inum); 
/* for a load instruction, reads store-buffer or memory and delivers data to target register,
 * for a write instruction, flushes value from store-buffer to memory 
 */

/*** COMMIT ***/

void EpsilonCommitInstruction(int cpu, Inum inum);
/* Notifies EPSILON that instr 'i' has been commited.
 * Requires: instruction 'i' must be an instruction which has
 * already been fetched, but not yet committed or killed.
 */

void EpsilonTrapNotify(int tpuNum, Inum trapInum, int trapType);

void EpsilonTrapInstruction(int cpu, Inum inum);

void EpsilonCPUVectorInit(void);

void PrintAllInflightInstructions(EpsilonState *epe);



#ifndef PMINT_INIT
#define PMINT_INIT(npes)
#endif

#ifndef PMINT_CPU_CYCLE
#define PMINT_CPU_CYCLE() NOTREACHED()
#endif

#ifndef PMINT_COPYIN
#define PMINT_COPYIN()
#endif
#ifndef PMINT_COPYOUT
#define PMINT_COPYOUT()
#endif

#endif /* EPSILON_H */