OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_47/] [or1ksim/] [cpu/] [or32/] [execute.c] - Rev 464

Go to most recent revision | Compare with Previous | Blame | View Log

/* execute.c -- OR1K architecture dependent simulation
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
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.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
/* Most of the OR1K simulation is done in here. */
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
 
#include "config.h"
#include "arch.h"
#include "opcode/or32.h"
#include "branch_predict.h"
#include "abstract.h"
#include "labels.h"
#include "parse.h"
#include "trace.h"
#include "execute.h"
#include "stats.h"
#include "except.h"
#include "sprs.h"
#include "sim-config.h"
#include "debug_unit.h"
 
/* General purpose registers. */
machword reg[MAX_GPRS];
 
/* Instruction queue */
struct iqueue_entry iqueue[20];
 
/* Is current insn in execution a delay insn? */
int delay_insn;
 
/* Benchmark multi issue execution */
int multissue[20];
int supercycles;
int issued_per_cycle = 4;
int hazardwait = 0;
int nops = 0;
int nop_period = 0;
int nop_maxperiod = 0;
 
/* Whether break was hit - so we can step over a break */
static int break_just_hit = 0;
 
/* freemem 'pointer' */
extern unsigned long freemem;
 
/* Completition queue */
struct iqueue_entry icomplet[20];
 
/* Program counter (and translated PC) */
unsigned long pc;
unsigned long pc_phy;
 
/* Previous program counter */
unsigned long prevpc = 0;
 
/* Temporary program counter */
unsigned long pcnext;
 
/* Delay instruction effective address register */
unsigned long pcdelay;
 
/* CCR */
int flag;
 
/* CCR (for dependency calculation) */
char ccr_flag[10] = "flag";
 
/* Cycles counts fetch stages */
int cycles;
 
/* Load and store stalls */
int loadcycles, storecycles;
 
/* Local data needed for execution.  */
static struct iqueue_entry *cur;
static int next_delay_insn;
static int breakpoint;
static unsigned long *op;
static int num_op;
 
/* Implementation specific.
   Get an actual value of a specific register. */
 
machword eval_reg(int regno)
{
  if (regno < MAX_GPRS) {
    int delta = (cycles - raw_stats.reg[regno]);
 
    if (delta < RAW_RANGE)
      raw_stats.range[delta]++;
    debug(9, "atoi ret1\n");
    return reg[regno];
  } else {
    printf("\nABORT: read out of registers\n");
    cont_run = 0;
    return 0;
  }
}
 
/* Implementation specific.
   Set a specific register with value. */
 
void set_reg32(int regno, unsigned long value)
{
#if 0   
  if (strcmp(regstr, FRAME_REG) == 0) {
    printf("FP (%s) modified by insn at %x. ", FRAME_REG, pc);
    printf("Old:%.8lx  New:%.8lx\n", eval_reg(regno), value);
  }
 
  if (strcmp(regstr, STACK_REG) == 0) {
    printf("SP (%s) modified by insn at %x. ", STACK_REG, pc);
    printf("Old:%.8lx  New:%.8lx\n", eval_reg(regmo), value);
  }
#endif
  if (regno == 0)               /* gpr0 is always zero */
    value = 0;
 
  if (regno < MAX_GPRS) {
    reg[regno] = value;
    raw_stats.reg[regno] = cycles;
  } else {
    printf("\nABORT: write out of registers\n");
    cont_run = 0;
  }
}
 
/* Does srcoperand depend on computation of dstoperand? Return
   non-zero if yes.
 
 Cycle t                 Cycle t+1
dst: irrelevant         src: immediate                  always 0
dst: reg1 direct        src: reg2 direct                0 if reg1 != reg2
dst: reg1 disp          src: reg2 direct                always 0
dst: reg1 direct        src: reg2 disp                  0 if reg1 != reg2
dst: reg1 disp          src: reg2 disp                  always 1 (store must
                                                        finish before load)
dst: flag               src: flag                       always 1
*/
 
int depend_operands(prev, next)
     struct iqueue_entry *prev;
     struct iqueue_entry *next;
{
  /* Find destination type. */
  unsigned long type = 0;
  int i = 0;
  if (or32_opcodes[prev->insn_index].flags & OR32_W_FLAG
      && or32_opcodes[next->insn_index].flags & OR32_R_FLAG)
    return 1;
 
  while (!(prev->op[i + MAX_OPERANDS] & OPTYPE_LAST))
    if (prev->op[i + MAX_OPERANDS] & OPTYPE_DST)
      {
        type = prev->op[i + MAX_OPERANDS];
        break;
      }
    else
      i++;
 
  /* We search all source operands - if we find confict => return 1 */
  i = 0;
  while (!(next->op[i + MAX_OPERANDS] & OPTYPE_LAST))
    if (!(next->op[i + MAX_OPERANDS] & OPTYPE_DST))
      {
        if (next->op[i + MAX_OPERANDS] & OPTYPE_DIS)
          if (type & OPTYPE_DIS)
            return 1;
          else if (next->op[i] == prev->op[i]
                   && (next->op[i + MAX_OPERANDS] & OPTYPE_REG))
            return 1;
        if (next->op[i] == prev->op[i]
            && (next->op[i + MAX_OPERANDS] & OPTYPE_REG)
            && (type & OPTYPE_REG))
          return 1;
        i++;
      }
    else
      i++;
  return 0;
}
 
/* Implementation specific.
   Parses and returns operands. */
 
static void
eval_operands (unsigned long insn, int insn_index, int* breakpoint)
{
  struct insn_op_struct *opd = op_start[insn_index];
  unsigned long data = 0;
  int dis = 0;
  int no = 0;
  while (1)
    {
      unsigned long tmp = 0, nbits = 0;
      while (1)
        {         
          tmp |= ((insn  >> (opd->type & OPTYPE_SHR)) & ((1 << opd->data) - 1)) << nbits;
          nbits += opd->data;
          if (opd->type & OPTYPE_OP)
            break;
          opd++;
        }
 
      /* Do we have to sign extend? */
      if (opd->type & OPTYPE_SIG)
        {
          int sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
          if (tmp & (1 << sbit))
            tmp |= 0xFFFFFFFF << sbit;
        }
      if (opd->type & OPTYPE_DIS) {
        /* We have to read register later.  */
        data += tmp;
        dis = 1;
      } else
        {
          if (dis && (opd->type & OPTYPE_REG))
            op[no] = data + eval_reg (tmp);
          else
            op[no] = tmp;
          op[no + MAX_OPERANDS] = opd->type | (dis ? OPTYPE_DIS : 0);
          no++;
          data = 0;
          dis = 0;
        }
      if(opd->type & OPTYPE_LAST)
        return;
      opd++;
    }
  num_op = no;
}
 
/* Implementation specific.
   Evaluates source operand op_no. */
 
unsigned long eval_operand32 (int op_no, int *breakpoint)
{
  debug (9, "%i %08X\n", op_no, op[op_no + MAX_OPERANDS]);
  if (op[op_no + MAX_OPERANDS] & OPTYPE_DIS) {
    if (op[op_no] & 0x03) {
      except_handle (EXCEPT_ALIGN, op[op_no]);
      return 0;
    }
    return eval_mem32 (op[op_no], breakpoint);
  }
  else if (op[op_no + MAX_OPERANDS] & OPTYPE_REG)
    return eval_reg (op[op_no]);
  else 
    return op[op_no];
}
 
/* Implementation specific.
   Evaluates source operand op_no. */
 
unsigned long eval_operand16 (int op_no, int *breakpoint)
{
  debug (9, "%i %08X\n", op_no, op[op_no + MAX_OPERANDS]);
  if (op[op_no + MAX_OPERANDS] & OPTYPE_DIS) {
    if (op[op_no] & 0x01) {
      except_handle (EXCEPT_ALIGN, op[op_no]);
      return 0;
    }
    return eval_mem16 (op[op_no], breakpoint);
  }
  else {
    fprintf (stderr, "Invalid operand type.\n");
    exit (1);
  }
}
 
/* Implementation specific.
   Evaluates source operand op_no. */
 
unsigned long eval_operand8 (int op_no, int *breakpoint)
{
  debug (9, "%i %08X\n", op_no, op[op_no + MAX_OPERANDS]);
  if (op[op_no + MAX_OPERANDS] & OPTYPE_DIS)
    return eval_mem8 (op[op_no], breakpoint);
  else {
    fprintf (stderr, "Invalid operand type.\n");
    exit (1);
  }
}
 
/* Implementation specific.
   Set destination operand (register direct, register indirect
   (with displacement) with value. */
 
void set_operand32(int op_no, unsigned long value, int* breakpoint)
{
  /* Mark this as destination operand.  */
  op[op_no + MAX_OPERANDS] |= OPTYPE_DST;
  if (op[op_no + MAX_OPERANDS] & OPTYPE_DIS) {
    if (op[op_no] & 0x03) {
      except_handle (EXCEPT_ALIGN, op[op_no]);
      return;
    }
    set_mem32(op[op_no], value, breakpoint);
  }
  else if (op[op_no + MAX_OPERANDS] & OPTYPE_REG) {
    set_reg32(op[op_no], value);
    value & 0x80000000 ? setsprbits (SPR_SR, SPR_SR_OV, 1) : setsprbits (SPR_SR, SPR_SR_OV, 0);
  }
  else
    {
      fprintf (stderr, "Invalid operand type.\n");
      exit (1);
    }
}
 
/* Implementation specific.
   Set destination operand (register direct, register indirect
   (with displacement) with value. */
 
void set_operand16(int op_no, unsigned long value, int* breakpoint)
{
  /* Mark this as destination operand.  */
   op[op_no + MAX_OPERANDS] |= OPTYPE_DST;
  if (op[op_no + MAX_OPERANDS] & OPTYPE_DIS) {
     if (op[op_no] & 0x01) {
      except_handle (EXCEPT_ALIGN, op[op_no]);
      return;
    }
    set_mem16(op[op_no], value, breakpoint);
  }
  else 
    {
      fprintf (stderr, "Invalid operand type.\n");
      exit (1);
    }
}
 
/* Implementation specific.
   Set destination operand (register direct, register indirect
   (with displacement) with value. */
 
void set_operand8(int op_no, unsigned long value, int* breakpoint)
{
  /* Mark this as destination operand.  */
  op[op_no + MAX_OPERANDS] |= OPTYPE_DST;
  if (op[op_no + MAX_OPERANDS] & OPTYPE_DIS)
    set_mem8(op[op_no], value, breakpoint);
  else 
    {
      fprintf (stderr, "Invalid operand type.\n");
      exit (1);
    }
}
 
void reset()
{
  cycles = 0;
  supercycles = 0;
  loadcycles = 0;
  storecycles = 0;
  memset(reg, 0, sizeof(reg));
  memset(iqueue, 0, sizeof(iqueue));
  memset(icomplet, 0, sizeof(icomplet));
 
  /* Cpu configuration */
  mtspr(SPR_UPR, config.cpu.upr);
  setsprbits(SPR_VR, SPR_VR_VER, config.cpu.ver);
  setsprbits(SPR_VR, SPR_VR_REV, config.cpu.rev);
 
  pcnext = 0x0; /* MM1409: All programs should start at reset vector entry!  */
  printf ("Starting at 0x%08x\n", pcnext);
  pc = pcnext;
  pc_phy = pc;
  pcnext += 4;
  ResetDebugUnit();
  debug(1, "reset ...\n");
 
  /* MM1409: All programs should set their stack pointer!  */
  except_handle(EXCEPT_RESET, 0);
}
 
int DIR_insn_injected = 0; /* CZ 21/06/01 */
/* Modified by CZ 26/05/01 for new mode execution */
/* Fetch returns nonzero if instruction should NOT be executed.  */
inline int fetch() {
  struct mem_entry *entry;
  debug(5, "fetch()\n");
 
  /* Do this here rather than update_pc so the reset exception
     will happen normally. NOTE: During debugging and
     modification of the simulator, please keep in mind that
     pc and pcnext are NOT guaranteed to be at their correct
     values until after this is called. If you add stuff to 
     the main loop in toplevel.c before this call, you may
     not get correct results. This can safely be moved to
     the toplevel.c main loop, as long as the fetch() routine
     is not called from anywhere else in the code. I have
     placed it here for safety.  CZ 21/06/01 */
 
// SIMON
  if (!pending.valid)
    pc_phy = translate_vrt_to_phy_add(pc);
 
  PrepareException();    /* Update the pc for pending exceptions */
 
  /* MM: Check for breakpoint.  This has to be done in fetch cycle,
     because of peripheria.  
     MM1709: if we cannot access the memory entry, we could not set the
     breakpoint earlier, so just chech the breakpoint list.  */
  if(has_breakpoint (pc_phy) && !break_just_hit) {
    break_just_hit = 1;
    return 1; /* Breakpoint set. */
  }
  break_just_hit = 0;
 
  /* Cycles after reset. */
  cycles++;
 
  /* Added by CZ...catch alignment exception here */
  if(pc_phy & 0x03)
    {
      except_handle(EXCEPT_ALIGN, 0);
      return 0; /* We will fetch exception wrapper at new location.  */
    }
 
#if 0
  if(pc_phy > MEMORY_START + MEMORY_LEN)
    pc_phy %= MEMORY_START + MEMORY_LEN;
#endif 
 
  /* Fetch instruction. */
  /* CZ 21/06/01: If there is an instruction waiting in the
     debug unit DIR, execute that first! Note the insn_addr
     may not be valid in this instance....hope that doesn't
     hurt. */
  {
    unsigned int _insn;
 
    if(!DEBUG_ENABLED && !OverrideFetch(&_insn))
      {
//        _insn = eval_mem32 (pc_phy, &breakpoint);
        _insn = eval_insn (pc_phy, &breakpoint);
        iqueue[0].insn_addr = pc;
      }
    else
      {
        iqueue[0].insn_addr = -1;
        DIR_insn_injected = 1;
      }
 
    iqueue[0].insn_index = insn_decode(_insn);
    iqueue[0].insn = _insn;
  }
 
  /* update_pc will be called after execution */
 
  return 0;
}
 
/* This code actually updates the PC value. CZ 21/06/01 */
inline void _execute_update_pc(unsigned long t_pc,unsigned long t_pcnext)
{
  prevpc = pc;
  pc = t_pc;
  pcnext = t_pcnext;
 
  /* Simulate instruction cache and IMMU. */
/*  pc_phy = translate_vrt_to_phy_add(pc);
 
  if(!verify_memoryarea(pc_phy))
    except_handle(EXCEPT_BUSERR, pc);
*/
}
 
/* Added by CZ on 27/05/01 */
/* Modified 21/06/01: If a breakpoint exception has stalled
   the cpu, then we do not want to update the PC. This causes
   GDB to barf uncontrollably. We act normally if the PC
   is not stalled, or precalculate the values that will be
   used if the PC is stalled. These are passed to prepare
   exception, which will call execute_update_pc at the
   appropriate time */
 
inline void update_pc()
{
  unsigned long t_pc = pcnext;
  unsigned long t_pcnext = delay_insn ? pcdelay : pcnext+4;
  extern int cpu_stalled;  /* CZ from debug_interface */
 
  /* If an insn was injected, don't increment the PC value,
     as it should not affect the existing instruction stream */
  if(DEBUG_ENABLED && DIR_insn_injected)
    {
      t_pc = pc;
      t_pcnext = delay_insn ? pcdelay : pcnext;
    }
  DIR_insn_injected = 0;
 
  if(!cpu_stalled)
    _execute_update_pc(t_pc,t_pcnext);
  else
    PrepareExceptionPC(t_pc,t_pcnext);
 
  nop_period++;
}
 
 
inline void analysis()
{
  if (config.cpu.dependstats)
    /* Instruction waits in completition buffer until retired. */
    memcpy (&icomplet[0], &iqueue[0], sizeof (struct iqueue_entry));
 
  if (config.sim.history) {
    int i;
 
    /* History of execution */
    for (i = HISTEXEC_LEN - 1; i; i--)
      histexec[i] = histexec[i - 1];
    histexec[0] = icomplet[0].insn_addr;        /* add last insn */
  }
}
 
 
/* Execution logger.  */
inline void dump_exe_log()
{
  int i = iqueue[0].insn_addr;
 
  fprintf(runtime.sim.fexe_log, "\nEXECUTED(): %.8lx:  ", i);
  fprintf(runtime.sim.fexe_log, "%.2x%.2x", evalsim_mem8(i), evalsim_mem8(i + 1));
  fprintf(runtime.sim.fexe_log, "%.2x%.2x", evalsim_mem8(i + 2), evalsim_mem8(i + 3));
  for(i = 0; i < MAX_GPRS; i++) {
    if (i % 4 == 0)
      fprintf(runtime.sim.fexe_log, "\n");
    fprintf(runtime.sim.fexe_log, "GPR%2u: %.8lx  ", i, reg[i]);
  }
  fprintf(runtime.sim.fexe_log, "\n");
  fprintf(runtime.sim.fexe_log, "SR   : %.8lx  ", mfspr(SPR_SR));  
  fprintf(runtime.sim.fexe_log, "EPCR0: %.8lx  ", mfspr(SPR_EPCR_BASE));
  fprintf(runtime.sim.fexe_log, "EEAR0: %.8lx  ", mfspr(SPR_EEAR_BASE));
  fprintf(runtime.sim.fexe_log, "ESR0 : %.8lx\n", mfspr(SPR_ESR_BASE));
}
 
void dumpreg()
{
  int i;
 
  printf("IQ[0]:");
  dumpmemory(iqueue[0].insn_addr, iqueue[0].insn_addr + 4, 1, 0);
  printf(" (just executed)\tCYCLES: %u \n", cycles);
  if (config.cpu.superscalar)
    printf ("Superscalar CYCLES: %u", supercycles);
  if (config.cpu.hazards)
    printf ("  HAZARDWAIT: %u\n", hazardwait);
  else
    if (config.cpu.superscalar)
      printf ("\n");
 
  if (config.sim.verbose) {
    printf("Additional LOAD CYCLES: %u  STORE CYCLES: %u\n", loadcycles, storecycles);
    printf("l.nop  count: %u  maxgap: %u\nPC:", nops, nop_maxperiod);
  } else 
    printf ("PC:");
  dumpmemory(pc, pc + 4, 1, 0);
  printf(" (next insn) %s", (delay_insn?"(delay insn)":""));
  for(i = 0; i < MAX_GPRS; i++) {
    if (i % 4 == 0)
      printf("\n");
    printf("GPR%.2u: %.8lx  ", i, reg[i]);
  }
  printf("flag: %u\n", flag);
}
 
/* Address calculation changed by CZ on 27/05/01 */
inline void decode_execute(struct iqueue_entry *current,int debug)
{
  next_delay_insn = 0;
  breakpoint = 0;
 
  if(DEBUG_ENABLED && CheckDebugUnit(DebugInstructionFetch,pc_phy))
    breakpoint++;
 
  cur = current;  
  cur->func_unit = unknown;
  op = &cur->op[0];
 
  /* printf("0x%04x: Executing \"%s\"\n",pc,cur->insn); */
 
#ifndef HAS_EXECUTION
#error HAS_EXECUTION has to be defined in order to execute programs.
#endif
 
  /* CZ 06/09/01 ... When we are debugging or creating a trace, we
     want to create a string representation of the insn so that we
     can write it out to a file or see what happened. The debug will
     be true if a trace is enabled or it has been manually turned
     on. Otherwise, it will be skipped in order to speed execution
     time. */
 
  if(debug)
    disassemble_insn(cur->insn);
 
  if (cur->insn_index < 0)
    l_invalid();
  else
    {
      eval_operands (cur->insn, cur->insn_index, &breakpoint);
      or32_opcodes[cur->insn_index].exec();
    }
 
  /* Check for range exception */
  if (getsprbits (SPR_SR, SPR_SR_OV) && getsprbits (SPR_SR, SPR_SR_OVE))
    except_handle (EXCEPT_RANGE, 0);
 
  if (config.cpu.dependstats) {
    /* Dynamic, dependency stats. */
    adddstats((char *)insn_name(icomplet[0].insn_index), (char *)insn_name(iqueue[0].insn_index), 1, check_depend());
 
    /* Dynamic, functional units stats. */
    addfstats(icomplet[0].func_unit, iqueue[0].func_unit, 1, check_depend());
 
    /* Dynamic, single stats. */
    addsstats((char *)insn_name(iqueue[0].insn_index), 1, 0);
  }
 
  if (config.cpu.superscalar) {
    if ((cur->func_unit == branch) || (cur->func_unit == jump))
      storecycles += 0;
 
    if (cur->func_unit == store)
      storecycles += 1;
 
    if (cur->func_unit == load)
      loadcycles += 1;
#if 0        
    if ((icomplet[0].func_unit == load) && check_depend())
      loadcycles++;
#endif
 
    /* Pseudo multiple issue benchmark */
    if ((multissue[cur->func_unit] < 1) || (check_depend())
                    || (issued_per_cycle < 1)
        ) {
      int i;
      for (i = 0; i < 20; i++)
        multissue[i] = 2;
      issued_per_cycle = 2;
      supercycles++;
      if (check_depend())
        hazardwait++;
      multissue[unknown] = 2;
      multissue[shift] = 2;
      multissue[compare] = 1;
      multissue[branch] = 1;
      multissue[jump] = 1;
      multissue[extend] = 2;
      multissue[nop] = 2;
      multissue[move] = 2;
      multissue[movimm] = 2;
      multissue[arith] = 2;
      multissue[store] = 2;
      multissue[load] = 2;
    }
    multissue[cur->func_unit]--;
    issued_per_cycle--;
  }
  delay_insn = next_delay_insn;
 
  if(breakpoint)
    except_handle(EXCEPT_BREAK,0);
 
  return;
}
 
/******************************************
 *    Instruction specific functions.     *
 ******************************************/
 
void l_sfne() {
  cur->func_unit = compare;
  flag = eval_operand32(0, &breakpoint) != eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_bf() {
  cur->func_unit = branch;
  if (eval_operand32(0, &breakpoint) >= pc)
    mstats.bnez.forward++;
  else
    mstats.bnez.backward++;
  mstats.sbp_bf.all++;
  if (flag) {
    debug(5, "\nl.bf relative: pc=%x pcnext=%x\n", pc, pcnext);
    pcdelay = pc + (signed)eval_operand32(0, &breakpoint) * 4;
 
    if (eval_operand32(0, &breakpoint) < pc)
      mstats.sbp_bf.correct++;
    mstats.bnez.taken++;
    bpb_update(cur->insn_addr, 1);
    btic_update(pcnext);
    next_delay_insn = 1;
  } else {
    mstats.bnez.nottaken++;
    bpb_update(cur->insn_addr, 0);
    btic_update(pc);
  }
}
void l_add() {
  signed long temp1;
  signed char temp4;
 
  cur->func_unit = arith;  
  temp1 = (signed long)eval_operand32(2, &breakpoint)+(signed long)eval_operand32(1, &breakpoint);
  set_operand32(0, temp1, &breakpoint);
 
  temp4 = temp1;
  if (temp4 == temp1)
    mstats.byteadd++;
}
void l_sw() {  
  cur->func_unit = store;
  set_operand32(0, eval_operand32(1, &breakpoint), &breakpoint);
}
void l_sb() {
  cur->func_unit = store;
  set_operand8(0, eval_operand32(1, &breakpoint), &breakpoint);
}
void l_sh() {
  cur->func_unit = store;
  set_operand16(0, eval_operand32(1, &breakpoint), &breakpoint);
}
void l_lwz() {
  unsigned long val;
  cur->func_unit = load;
  val = eval_operand32(1, &breakpoint);
  /* If eval opreand produced exception don't set anything */
  if (pending.valid == 1)
    return;
  set_operand32(0, val, &breakpoint);
}
void l_lbs() {
  signed char val;
  cur->func_unit = load;
  val = eval_operand8(1, &breakpoint);
  /* If eval opreand produced exception don't set anything */
  if (pending.valid == 1)
    return;
  set_operand32(0, val, &breakpoint);
}
void l_lbz() {  
  unsigned char val;
  cur->func_unit = load;
  val = eval_operand8(1, &breakpoint);
  /* If eval opreand produced exception don't set anything */
  if (pending.valid == 1)
    return;
  set_operand32(0, val, &breakpoint);
}
void l_lhs() {  
  signed short val;
  cur->func_unit = load;
  val = eval_operand16(1, &breakpoint);
  /* If eval opreand produced exception don't set anything */
  if (pending.valid == 1)
    return;
  set_operand32(0, val, &breakpoint);
}
void l_lhz() {  
  unsigned short val;
  cur->func_unit = load;
  val = eval_operand16(1, &breakpoint);
  /* If eval opreand produced exception don't set anything */
  if (pending.valid == 1)
    return;
  set_operand32(0, val, &breakpoint);
}
void l_movhi() {
  cur->func_unit = movimm;
  set_operand32(0, eval_operand32(1, &breakpoint) << 16, &breakpoint);
}
void l_and() {
  cur->func_unit = arith;
  set_operand32(0, eval_operand32(1, &breakpoint) & (unsigned)eval_operand32(2, &breakpoint), &breakpoint);
}
void l_or() {
  cur->func_unit = arith;
  set_operand32(0, eval_operand32(1, &breakpoint) | (unsigned)eval_operand32(2, &breakpoint), &breakpoint);
}
void l_xor() {
  cur->func_unit = arith;
  set_operand32(0, eval_operand32(1, &breakpoint) ^ (signed)eval_operand32(2, &breakpoint), &breakpoint);
}
void l_sub() {
  cur->func_unit = arith;
  set_operand32(0, (signed long)eval_operand32(1, &breakpoint) - (signed long)eval_operand32(2, &breakpoint), &breakpoint);
}
/*int mcount = 0;*/
void l_mul() {
  signed long temp3, temp2, temp1;
 
  cur->func_unit = arith;
  set_operand32(0, (signed long)eval_operand32(1, &breakpoint) * (signed long)eval_operand32(2, &breakpoint), &breakpoint);
  /*if (!(mcount++ & 1023)) {
    printf ("[%i]\n",mcount);
    }*/
}
void l_div() {
  signed long temp3, temp2, temp1;
 
  cur->func_unit = arith;
  temp3 = eval_operand32(2, &breakpoint);
  temp2 = eval_operand32(1, &breakpoint);
  if (temp3)
    temp1 = temp2 / temp3;
  else {
    except_handle(EXCEPT_ILLEGAL, iqueue[0].insn_addr);
    return;
  }
  set_operand32(0, temp1, &breakpoint);
}
void l_divu() {
  unsigned long temp3, temp2, temp1;
 
  cur->func_unit = arith;
  temp3 = eval_operand32(2, &breakpoint);
  temp2 = eval_operand32(1, &breakpoint);
  temp1 = temp2 / temp3;
  /* cycles += 16; */
  set_operand32(0, temp1, &breakpoint);
}
void l_sll() {
  int sign = 1;
  cur->func_unit = shift;
  if ((signed)eval_operand32(1, &breakpoint) < 0)
    sign = -1;
  /* cycles += 2; */
  set_operand32(0, eval_operand32(1, &breakpoint) << eval_operand32(2, &breakpoint), &breakpoint);
}
void l_sra() {
  unsigned long sign = 0;
  cur->func_unit = shift;
 
  if ((signed)eval_operand32(1, &breakpoint) < 0)
    sign = -1;
  /* cycles += 2; */
  set_operand32(0, (signed)eval_operand32(1, &breakpoint) >> eval_operand32(2, &breakpoint), &breakpoint);
}
void l_srl() {
  cur->func_unit = shift;
  /* cycles += 2; */
  set_operand32(0, eval_operand32(1, &breakpoint) >> eval_operand32(2, &breakpoint), &breakpoint);
}
void l_j() {
  debug(5, "\nl.j relative: pc=%x pcnext=%x\n", pc, pcnext);
  pcdelay = pc + (signed)eval_operand32(0, &breakpoint) * 4;
  cur->func_unit = jump;
  next_delay_insn = 1;
}
void l_jal() {
  debug(5, "\nl.jal relative: pc=%x pcnext=%x\n", pc, pcnext);
  pcdelay = pc + (signed)eval_operand32(0, &breakpoint) * 4;
 
  cur->func_unit = jump;
  set_reg32(LINK_REGNO, pc + 8);
  slp_func_entry();
  next_delay_insn = 1;
  if (config.sim.profile) {
    struct mem_entry *entry;    
    struct label_entry *tmp;
    if (verify_memoryarea(pcdelay) && (tmp = get_label (pcdelay)))
      fprintf (runtime.sim.fprof, "+%08X %08X %08X %s\n", cycles, pc + 8, pcdelay, tmp->name);
    else
      fprintf (runtime.sim.fprof, "+%08X %08X %08X @%08X\n", cycles, pc + 8, pcdelay, pcdelay);
  }
}
void l_jalr() {
  cur->func_unit = jump;
  pcdelay = eval_operand32(0, &breakpoint);
  set_reg32(LINK_REGNO, pc + 8);
  slp_func_exit();
  next_delay_insn = 1;
  if (config.sim.profile)
    fprintf (runtime.sim.fprof, "-%08X %08X\n", cycles, pcdelay);
}
void l_jr() {
  cur->func_unit = jump;
  pcdelay = eval_operand32(0, &breakpoint);
  next_delay_insn = 1;
}
void l_rfe() {
  cur->func_unit = exception;
  pcnext = mfspr(SPR_EPCR_BASE);
  mtspr(SPR_SR, mfspr(SPR_ESR_BASE));
}
void l_nop() {
  cur->func_unit = nop;
  if (nop_period > nop_maxperiod)
    nop_maxperiod = nop_period;
  nop_period = 0;
  nops++;
}
void l_bnf() {
  cur->func_unit = branch;
  if (eval_operand32(0, &breakpoint) >= pc)
    mstats.beqz.forward++;
  else
    mstats.beqz.backward++;
  mstats.sbp_bnf.all++;
  if (flag == 0) {
    debug(5, "\nl.bnf relative: pc=%x pcnext=%x\n", pc, pcnext);
    pcdelay = pc + (signed)eval_operand32(0, &breakpoint) * 4;
 
    mstats.beqz.taken++;
    bpb_update(cur->insn_addr, 1);
    btic_update(pcnext);
    next_delay_insn = 1;
  } else {
    if (eval_operand32(0, &breakpoint) >= pc)
      mstats.sbp_bnf.correct++;
    mstats.beqz.nottaken++;
    bpb_update(cur->insn_addr, 0);
    btic_update(pc);
  }
}
void l_sfeq() {
  cur->func_unit = compare;
  flag = eval_operand32(0, &breakpoint) == eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_sfgts() {
  cur->func_unit = compare;
  flag = (signed)eval_operand32(0, &breakpoint) > (signed)eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_sfges() {
  cur->func_unit = compare;
  flag = (signed)eval_operand32(0, &breakpoint) >= (signed)eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_sflts() {
  cur->func_unit = compare;
  flag = (signed)eval_operand32(0, &breakpoint) < (signed)eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_sfles() {
  cur->func_unit = compare;
  flag = (signed)eval_operand32(0, &breakpoint) <= (signed)eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_sfgtu() {
  cur->func_unit = compare;
  flag = (unsigned)eval_operand32(0, &breakpoint) > (unsigned)eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_sfgeu() {
  cur->func_unit = compare;
  flag = (unsigned)eval_operand32(0, &breakpoint) >= (unsigned) eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_sfltu() {
  cur->func_unit = compare;
  flag = (unsigned)eval_operand32(0, &breakpoint) < (unsigned)eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_sfleu() {
  cur->func_unit = compare;
  flag = (unsigned)eval_operand32(0, &breakpoint) <= (unsigned)eval_operand32(1, &breakpoint);
  setsprbits(SPR_SR, SPR_SR_F, flag);
}
void l_mtspr() {
  cur->func_unit = move;
  if (mfspr(SPR_SR) & SPR_SR_SUPV)
    mtspr(eval_operand32(0, &breakpoint) + eval_operand32(2, &breakpoint), eval_operand32(1, &breakpoint));
  else {
    printf("WARNING: trying to write SPR while SR[SUPV] is cleared.\n");
    cont_run = 0;
  }
}
void l_mfspr() {
  cur->func_unit = move;
  if (mfspr(SPR_SR) & SPR_SR_SUPV)
    set_operand32(0, mfspr(eval_operand32(1, &breakpoint) + eval_operand32(2, &breakpoint)), &breakpoint);
  else {
    set_operand32(0, 0, &breakpoint);
    printf("WARNING: trying to read SPR while SR[SUPV] is cleared.\n");
    cont_run = 0;
  }
}
void l_sys() {
 
  if (eval_operand32(0, &breakpoint) > 200) {
    unsigned long stackaddr, fmtaddr, args;
    switch (eval_operand32(0, &breakpoint)) {
    case 201:
      set_reg32 (RETURNV_REGNO, cycles + loadcycles + storecycles);
      break;
    case 202:
      stackaddr = eval_reg(4);
      simprintf(stackaddr, eval_reg(3));
      debug(5, "simprintf %x %x %x\n", stackaddr, fmtaddr, args);
      break;
    case 203:
      printf("syscall exit(%d)\n", eval_reg (3));
      cont_run = 0;
      break;
    case 204: {
      unsigned long startaddr;
      unsigned long endaddr;
 
      /*                                                if ((startaddr = eval_mem32(eval_reg("r4"))) == -1)
                                                        startaddr = (freemem & ~(PAGE_SIZE)) + PAGE_SIZE; */
      startaddr = 0x80000000;
      printf("sys 204: startaddr=%x virtphy=%x\n", startaddr, eval_reg(5));
      fflush(stdout);
      endaddr = loadcode(simgetstr(stackaddr, eval_reg(3)), startaddr, eval_reg(5));
      set_reg32 (LINK_REGNO, endaddr);
      /* setsim_mem32(eval_reg(4), startaddr);
         setsim_mem32(eval_reg(5), endaddr);*/
      break;
    }
    }
  }
  else except_handle(EXCEPT_SYSCALL, 0);
}
 
void l_trap() {
  except_handle(EXCEPT_TRAP, 0);
}
 
void l_mac() {
  sprword lo, hi;
  LONGEST l;
  long x, y;
  cur->func_unit = mac;
  lo = mfspr (SPR_MACLO);
  hi = mfspr (SPR_MACHI);
  x = eval_operand32(0, &breakpoint);
  y = eval_operand32(1, &breakpoint);
  //printf ("[%08x,%08x]\t", (unsigned long)(x), (unsigned long)(y));
  l = (ULONGEST)lo | ((LONGEST)hi << 32);
  l += (LONGEST) x * (LONGEST) y;
 
  /* This implementation is very fast - it needs only one cycle for mac.  */
  lo = ((ULONGEST)l) & 0xFFFFFFFF;
  hi = ((LONGEST)l) >> 32;
  mtspr (SPR_MACLO, lo);
  mtspr (SPR_MACHI, hi);
  //printf ("(%08x,%08x)\n", hi, lo);
}
void l_msb() {
  sprword lo, hi;  
  LONGEST l;
  cur->func_unit = mac;
  lo = mfspr (SPR_MACLO);
  hi = mfspr (SPR_MACHI);
  l = (ULONGEST)lo | ((LONGEST)hi << 32);
  l -= (LONGEST) eval_operand32(0, &breakpoint) * (LONGEST)eval_operand32(1, &breakpoint);
 
  /* This implementation is very fast - it needs only one cycle for msb.  */
  lo = ((ULONGEST)l) & 0xFFFFFFFF;
  hi = ((LONGEST)l) >> 32;
  mtspr (SPR_MACLO, lo);
  mtspr (SPR_MACHI, hi);  
}
void l_macrc() {
  sprword lo, hi;
  LONGEST l;
  /* No need for synchronization here -- all MAC instructions are 1 cycle long.  */
  lo =  mfspr (SPR_MACLO);
  hi =  mfspr (SPR_MACHI);
  l = (ULONGEST) lo | ((LONGEST)hi << 32);
  l >>= 28;
  //printf ("<%08x>\n", (unsigned long)l);
  set_operand32(0, (long)l, &breakpoint);
  mtspr (SPR_MACLO, 0);
  mtspr (SPR_MACHI, 0);
}
void l_cust1() {
  /*int destr = cur->insn >> 21;
    int src1r = cur->insn >> 15;
    int src2r = cur->insn >> 9;*/
}
void l_cust2() {
}
void l_cust3() {
}
void l_cust4() {
}
void l_invalid() {
  except_handle(EXCEPT_ILLEGAL, iqueue[0].insn_addr);
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.