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

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [cpu/] [or32/] [dyn_rec.c] - Diff between revs 1452 and 1481

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 1452 Rev 1481
Line 286... Line 286...
 
 
static int sigsegv_state = 0;
static int sigsegv_state = 0;
static void *sigsegv_addr = NULL;
static void *sigsegv_addr = NULL;
 
 
void dyn_ret_stack_prot(void);
void dyn_ret_stack_prot(void);
void dump_held_xrefs(struct dyn_page *dp, FILE *f);
 
 
 
void dyn_sigsegv_debug(int u, siginfo_t *siginf, void *dat)
void dyn_sigsegv_debug(int u, siginfo_t *siginf, void *dat)
{
{
  struct dyn_page *dp;
  struct dyn_page *dp;
  FILE *f;
  FILE *f;
Line 335... Line 334...
 
 
      fclose(f);
      fclose(f);
    }
    }
    sigsegv_state++;
    sigsegv_state++;
  case 2:
  case 2:
    /* Dump the x-refs to disk */
 
    for(dp = cpu_state.dyn_pages; dp; dp = dp->next) {
 
      printf("Dumping cross references of 0x%"PRIxADDR" to disk\n", dp->or_page);
 
 
 
      sprintf(filen, "or_xref.%"PRIxADDR, dp->or_page);
 
      if(!(f = fopen(filen, "w"))) {
 
        fprintf(stderr, "Unable to open %s to dump cross references to: %s\n",
 
                filen, strerror(errno));
 
        continue;
 
      }
 
 
 
      fprintf(f, "Cross references in the page:\n");
 
      dump_xrefs(dp, f);
 
 
 
      fprintf(f, "\nCross references held by this page:\n");
 
      dump_held_xrefs(dp, f);
 
 
 
      fclose(f);
 
    }
 
    sigsegv_state++;
 
  case 3:
 
    /* Dump the contents of the stack */
    /* Dump the contents of the stack */
    printf("Stack dump: ");
    printf("Stack dump: ");
    fflush(stdout);
    fflush(stdout);
 
 
    num_trace = backtrace(trace, 10);
    num_trace = backtrace(trace, 10);
Line 378... Line 356...
      }
      }
      printf("\n");
      printf("\n");
      fflush(stdout);
      fflush(stdout);
    }
    }
    sigsegv_state++;
    sigsegv_state++;
  case 4:
  case 3:
    sim_done();
    sim_done();
  }
  }
}
}
 
 
void dump_xrefs(struct dyn_page *dp, FILE *f)
 
{
 
  struct x_ref *xref;
 
 
 
  fprintf(f, "--- Cross reference dump for %"PRIxADDR" at %p ---\n",
 
          dp->or_page, dp->host_page);
 
  for(xref = dp->xrefs; xref; xref = xref->next) {
 
    fprintf(f, "x-refed or location: 0x%"PRIxADDR", host-location: %p, ref: %i\n",
 
            xref->or_addr, xref->dyn_addr, xref->ref);
 
  }
 
  fprintf(f, "--- Cross reference dump end ---\n");
 
}
 
 
 
void dump_held_xrefs(struct dyn_page *dp, FILE *f)
 
{
 
  struct x_ref **xrefs;
 
 
 
  fprintf(f, "--- Held cross reference dump for %"PRIxADDR" at %p ---\n",
 
          dp->or_page, dp->host_page);
 
  for(xrefs = dp->held_xrefs; *xrefs; xrefs++)
 
    fprintf(f, "Holds an x-ref to 0x%"PRIxADDR", host-location: %p, ref: %i\n",
 
            (*xrefs)->or_addr, (*xrefs)->dyn_addr, (*xrefs)->ref);
 
  fprintf(f, "--- Held cross reference dump end ---\n");
 
}
 
 
 
static void add_to_dp(struct dyn_page *new)
static void add_to_dp(struct dyn_page *new)
{
{
  struct dyn_page *cur;
  struct dyn_page *cur;
  struct dyn_page *prev;
  struct dyn_page *prev;
 
 
Line 431... Line 384...
struct dyn_page *new_dp(oraddr_t page)
struct dyn_page *new_dp(oraddr_t page)
{
{
  struct dyn_page *dp = malloc(sizeof(struct dyn_page));
  struct dyn_page *dp = malloc(sizeof(struct dyn_page));
  dp->or_page = ADDR_PAGE(page);
  dp->or_page = ADDR_PAGE(page);
 
 
  /* Allocate xref terminator */
  dp->locs = malloc(sizeof(void *) * (PAGE_LEN / 4));
  dp->xrefs = NULL;
 
 
 
  dp->held_xrefs = malloc(sizeof(struct x_ref *));
 
  dp->held_xrefs[0] = NULL;
 
 
 
  dp->host_len = 0;
  dp->host_len = 0;
  dp->host_page = NULL;
  dp->host_page = NULL;
  dp->dirty = 1;
  dp->dirty = 1;
 
 
Line 460... Line 409...
    cur = cur->next;
    cur = cur->next;
  }
  }
  return NULL;
  return NULL;
}
}
 
 
/* Finds the dynamicly recompiled location of the given or address */
 
struct x_ref *find_host_x_ref(struct x_ref *x_refs, oraddr_t addr)
 
{
 
  /* FIXME: Optimise this by knowing that the x_refs array is orderd */
 
  while(x_refs && (x_refs->or_addr != addr)) x_refs = x_refs->next;
 
 
 
  return x_refs;
 
}
 
 
 
static void remove_xref(struct dyn_page *dp, struct x_ref *xref)
 
{
 
  struct x_ref *prev_xref;
 
 
 
  if(dp->xrefs == xref) {
 
    dp->xrefs = xref->next;
 
    free(xref);
 
    return;
 
  }
 
 
 
  prev_xref = dp->xrefs;
 
  while(prev_xref->next != xref)
 
    prev_xref = prev_xref->next;
 
 
 
  prev_xref->next = xref->next;
 
  free(xref);
 
}
 
 
 
struct x_ref *find_held_x_ref(struct x_ref **held_xrefs, oraddr_t or_addr)
 
{
 
  /* FIXME: Order this list in add_to_held_xrefs below and optimise this */
 
  while(*held_xrefs && ((*held_xrefs)->or_addr != or_addr)) held_xrefs++;
 
  return *held_xrefs;
 
}
 
 
 
void add_to_held_xrefs(struct dyn_page *dp, struct x_ref *xref)
 
{
 
  unsigned int i;
 
 
 
  for(i = 0; dp->held_xrefs[i]; i++);
 
 
 
  dp->held_xrefs = realloc(dp->held_xrefs, sizeof(struct x_ref *) * (i + 2));
 
  dp->held_xrefs[i] = xref;
 
  dp->held_xrefs[++i] = NULL;
 
}
 
 
 
/* This is called whenever the immu is either enabled/disabled or reconfigured
/* This is called whenever the immu is either enabled/disabled or reconfigured
 * while enabled.  This checks if an itlb miss would occour and updates the immu
 * while enabled.  This checks if an itlb miss would occour and updates the immu
 * hit delay counter */
 * hit delay counter */
void recheck_immu(int got_en_dis)
void recheck_immu(int got_en_dis)
{
{
Line 561... Line 465...
{
{
  int brk;
  int brk;
  oraddr_t pc = get_pc();
  oraddr_t pc = get_pc();
 
 
  if(!cpu_state.ts_current)
  if(!cpu_state.ts_current)
    upd_reg_from_t(pc);
    upd_reg_from_t(pc, 0);
 
 
  if(add_normal && do_stats) {
  if(add_normal && do_stats) {
    cpu_state.iqueue.insn_addr = pc;
    cpu_state.iqueue.insn_addr = pc;
    cpu_state.iqueue.insn = eval_insn_direct(pc, &brk, 1);
    cpu_state.iqueue.insn = eval_insn_direct(pc, &brk, 1);
    cpu_state.iqueue.insn_index = insn_decode(cpu_state.iqueue.insn);
    cpu_state.iqueue.insn_index = insn_decode(cpu_state.iqueue.insn);
 
    runtime.cpu.instructions++;
    analysis(&cpu_state.iqueue);
    analysis(&cpu_state.iqueue);
  }
  }
 
 
  /* Run the scheduler */
  /* Run the scheduler */
  if(add_normal)
  if(add_normal)
Line 583... Line 488...
}
}
 
 
/* Signals a page as dirty */
/* Signals a page as dirty */
void dirtyfy_page(struct dyn_page *dp)
void dirtyfy_page(struct dyn_page *dp)
{
{
  struct x_ref **held_xrefs;
 
  struct x_ref *xref;
 
  oraddr_t check;
  oraddr_t check;
 
 
  printf("Dirtyfying page 0x%"PRIxADDR"\n", dp->or_page);
  printf("Dirtyfying page 0x%"PRIxADDR"\n", dp->or_page);
 
 
  /* decrease the reference counts of the xrefs that we hold */
 
  for(held_xrefs = dp->held_xrefs; *held_xrefs; held_xrefs++)
 
    (*held_xrefs)->ref--;
 
  dp->held_xrefs = realloc(dp->held_xrefs, sizeof(struct x_ref *));
 
  dp->held_xrefs[0] = NULL;
 
 
 
  dp->dirty = 1;
  dp->dirty = 1;
 
 
  /* If the execution is currently in the page that was touched then recompile
  /* If the execution is currently in the page that was touched then recompile
   * it now and jump back to the point of execution */
   * it now and jump back to the point of execution */
  check = cpu_state.delay_insn ? cpu_state.pc_delay : get_pc() + 4;
  check = cpu_state.delay_insn ? cpu_state.pc_delay : get_pc() + 4;
  if(ADDR_PAGE(check) == dp->or_page) {
  if(ADDR_PAGE(check) == dp->or_page) {
    run_sched_out_of_line(1);
    run_sched_out_of_line(1);
    if(!(xref = find_host_x_ref(dp->xrefs, check))) {
 
      xref = add_to_xrefs(dp, check);
 
      add_to_held_xrefs(dp, xref);
 
    } else {
 
      if(!find_held_x_ref(dp->held_xrefs, check)) {
 
        add_to_held_xrefs(dp, xref);
 
        xref->ref++;
 
      }
 
    }
 
    recompile_page(dp);
    recompile_page(dp);
 
 
    cpu_state.delay_insn = 0;
    cpu_state.delay_insn = 0;
 
 
    /* Jump out to the next instruction */
    /* Jump out to the next instruction */
    or_longjmp(xref->dyn_addr);
    do_jump(check);
  }
  }
}
}
 
 
static void ship_gprs_out_t(struct op_queue *opq, int end, unsigned int *reg_t)
static void ship_gprs_out_t(struct op_queue *opq, int end, unsigned int *reg_t)
{
{
  int i;
  int i;
 
 
 
  /* Before takeing the temporaries out, temporarily remove the op_do_sched
 
   * operation such that dyn_page->ts_bound shall be correct before the
 
   * scheduler runs */
 
  if(end && opq->num_ops && (opq->ops[opq->num_ops - 1] == op_do_sched_indx)) {
 
    opq->num_ops--;
 
    ship_gprs_out_t(opq, end, reg_t);
 
    gen_op_do_sched(opq, 1);
 
    return;
 
  }
 
 
  for(i = 0; i < NUM_T_REGS; i++) {
  for(i = 0; i < NUM_T_REGS; i++) {
    if(reg_t[i] < 32)
    if(reg_t[i] < 32)
      gen_op_move_gpr_t[i][reg_t[i]](opq, end);
      gen_op_move_gpr_t[i][reg_t[i]](opq, end);
  }
  }
}
}
Line 690... Line 588...
  }
  }
 
 
  opq->num_ops++;
  opq->num_ops++;
}
}
 
 
 
static void gen_op_mark_loc(struct op_queue *opq, int end)
 
{
 
  add_to_opq(opq, end, op_mark_loc_indx);
 
}
 
 
/* Adds a parameter to the opq */
/* Adds a parameter to the opq */
void add_to_op_params(struct op_queue *opq, int end, unsigned long param)
void add_to_op_params(struct op_queue *opq, int end, unsigned long param)
{
{
  if(opq->num_ops_param == opq->ops_param_len) {
  if(opq->num_ops_param == opq->ops_param_len) {
    opq->ops_param_len += OPS_ENLARGE_BY * sizeof(int);
    opq->ops_param_len += OPS_ENLARGE_BY;
    if(!(opq->ops_param = realloc(opq->ops_param, opq->ops_param_len))) {
    if(!(opq->ops_param = realloc(opq->ops_param, opq->ops_param_len * sizeof(int)))) {
      fprintf(stderr, "OOM\n");
      fprintf(stderr, "OOM\n");
      exit(1);
      exit(1);
    }
    }
  }
  }
 
 
Line 733... Line 636...
/* Initialises the recompiler */
/* Initialises the recompiler */
void init_dyn_recomp(void)
void init_dyn_recomp(void)
{
{
  struct sigaction sigact;
  struct sigaction sigact;
  struct op_queue *opq;
  struct op_queue *opq;
  struct x_ref *xref;
 
  unsigned int i;
  unsigned int i;
 
 
  cpu_state.opqs = NULL;
  cpu_state.opqs = NULL;
 
 
  /* Allocate the operation queue list (+1 for the page chaining) */
  /* Allocate the operation queue list (+1 for the page chaining) */
Line 750... Line 652...
    /* initialise some fields */
    /* initialise some fields */
    opq->ops_len = 0;
    opq->ops_len = 0;
    opq->ops = NULL;
    opq->ops = NULL;
    opq->ops_param_len = 0;
    opq->ops_param_len = 0;
    opq->ops_param = NULL;
    opq->ops_param = NULL;
 
    opq->xref = 0;
 
 
    if(cpu_state.opqs)
    if(cpu_state.opqs)
      cpu_state.opqs->prev = opq;
      cpu_state.opqs->prev = opq;
 
 
    opq->next = cpu_state.opqs;
    opq->next = cpu_state.opqs;
    cpu_state.opqs = opq;
    cpu_state.opqs = opq;
  }
  }
 
 
  opq->prev = NULL;
  opq->prev = NULL;
 
 
  /* Allocate the x-ref structures that will be used for the infinite loop
 
   * instruction (l.j 0).  Allocate a whole page's worth just to make sure that
 
   * we will have enough */
 
  for(i = 0; i < (PAGE_LEN / 4); i++) {
 
    if(!(xref = malloc(sizeof(struct x_ref)))) {
 
      fprintf(stderr, "Out-of-memory while allocateing x-ref structures\n");
 
      exit(1);
 
    }
 
    xref->next = cpu_state.inf_xrefs;
 
    cpu_state.inf_xrefs = xref;
 
  }
 
 
 
  /* Just some value that we'll use as the base for our stack */
  /* Just some value that we'll use as the base for our stack */
  rec_stack_base = get_sp();
  rec_stack_base = get_sp();
 
 
  cpu_state.curr_page = NULL;
  cpu_state.curr_page = NULL;
  cpu_state.dyn_pages = NULL;
  cpu_state.dyn_pages = NULL;
Line 785... Line 676...
  memset(&sigact.sa_mask, 0, sizeof(sigact.sa_mask));
  memset(&sigact.sa_mask, 0, sizeof(sigact.sa_mask));
  sigact.sa_flags = SA_SIGINFO | SA_NOMASK;
  sigact.sa_flags = SA_SIGINFO | SA_NOMASK;
  if(sigaction(SIGSEGV, &sigact, NULL))
  if(sigaction(SIGSEGV, &sigact, NULL))
    printf("WARN: Unable to install SIGSEGV handler! Don't expect to be able to debug the recompiler.\n");
    printf("WARN: Unable to install SIGSEGV handler! Don't expect to be able to debug the recompiler.\n");
 
 
  /* Allocate memory for the rfe corss reference cache */
  /* Do architecture specific initialisation */
  if(!(cpu_state.rfe_held_xrefs = malloc(sizeof(struct xref *) * NUM_RFE_HELD))) {
 
    printf("OOM\n");
 
    exit(1);
 
  }
 
  cpu_state.rfe_held_xref_pos = 0;
 
  memset(cpu_state.rfe_held_xrefs, 0, sizeof(struct xref *) * NUM_RFE_HELD);
 
 
 
  init_dyn_rec();
  init_dyn_rec();
 
 
  /* FIXME: Find a better place for this */
  /* FIXME: Find a better place for this */
    { /* Needed by execution */
    { /* Needed by execution */
      extern int do_stats;
      extern int do_stats;
Line 805... Line 689...
    }
    }
 
 
  printf("Recompile engine up and running\n");
  printf("Recompile engine up and running\n");
}
}
 
 
/* rec_page is a physical address */
/* Adds code to the opq for the instruction pointed to by addr */
void recompile_page(struct dyn_page *dyn)
static void recompile_insn(struct op_queue *opq, oraddr_t addr, int delay_insn)
{
{
  unsigned int j, k;
 
  unsigned int reg_t[NUM_T_REGS];
 
  unsigned int pres_t[NUM_T_REGS]; /* Which temporary to preserve */
 
  unsigned int insn_index;
  unsigned int insn_index;
  int delay_insn = 0; /* Is the next instruction to be decoded in a delay slot*/
  unsigned int pres_t[NUM_T_REGS]; /* Which temporary to preserve */
  enum insn_type delay_insn_type = 0;
  orreg_t param[3];
  uint32_t insn;
  int i, j, k;
  int param_t[3]; /* Which temporary the parameters reside in */
  int param_t[3]; /* Which temporary the parameters reside in */
  int param_r[3]; /* is parameter a register */
  int param_r[3]; /* is parameter a register */
  orreg_t param[3];
 
  int param_num;
  int param_num;
  struct op_queue *opq = NULL;
  uint32_t insn;
  oraddr_t rec_addr = dyn->or_page;
 
  oraddr_t rec_page = dyn->or_page;
 
  struct x_ref *xref;
 
  int breakp;
  int breakp;
  struct dyn_page *prev_dp;
 
 
 
  struct insn_op_struct *opd;
  struct insn_op_struct *opd;
 
 
  /* The start of the next page */
 
  rec_page += PAGE_LEN;
 
 
 
  printf("Recompileing page %"PRIxADDR"\n", rec_addr);
 
  fflush(stdout);
 
 
 
  /* Mark all temporaries as not containing a register */
 
  for(j = 0; j < NUM_T_REGS; j++)
 
    reg_t[j] = 32; /* Out-of-range registers */
 
 
 
  dyn->delayr = -verify_memoryarea(rec_addr)->delayr;
 
 
 
  dyn->carrys_delay_slot = 0;
 
 
 
  /* Check if the previous page carries a delay slot over to this page */
 
  if((prev_dp = find_dynd_page(rec_addr - PAGE_LEN)))
 
    delay_insn = prev_dp->carrys_delay_slot;
 
 
 
  for(opq = cpu_state.opqs; rec_addr < rec_page; rec_addr += 4, opq = opq->next) {
 
    opq->num_ops = 0;
 
    opq->num_ops_param = 0;
 
    opq->jump_local = 0;
 
 
 
    opq->insn_addr = rec_addr;
 
 
 
    breakp = 0;
    breakp = 0;
    insn = eval_insn(rec_addr, &breakp);
  insn = eval_insn(addr, &breakp);
 
 
    /* FIXME: If a breakpoint is set at this location, insert exception code */
    /* FIXME: If a breakpoint is set at this location, insert exception code */
    if(breakp) {
    if(breakp) {
      fprintf(stderr, "FIXME: Insert breakpoint code\n");
      fprintf(stderr, "FIXME: Insert breakpoint code\n");
    }
    }
 
 
    insn_index = insn_decode(insn);
    insn_index = insn_decode(insn);
 
 
    /* FIXME: Optimise this by knowing that dyn->x_refs is ordered (ie. Don't
  /* Copy over the state of the temporaries to the next opq */
     *        call find_host_x_ref) */
  memcpy(opq->reg_t_d, opq->reg_t, sizeof(opq->reg_t));
    /* Check if this location is cross referenced */
 
    if((xref = find_host_x_ref(dyn->xrefs, rec_addr))) {
 
      /* If the x-refs reference count reached zero remove it */
 
      if(xref->ref) {
 
        /* If the current address is cross-referenced, the temporaries shall be
 
         * in an undefined state, so we must assume that no registers reside in
 
         * them */
 
        /* Ship out the current set of registers from the temporaries */
 
        if(opq->prev) {
 
          ship_gprs_out_t(opq->prev, 1, reg_t);
 
        }
 
        for(j = 0; j < NUM_T_REGS; j++)
 
          reg_t[j] = 32;
 
      } else {
 
        /* Remove x-ref */
 
        remove_xref(dyn, xref);
 
      }
 
    }
 
 
 
    memcpy(opq->reg_t, reg_t, sizeof(reg_t));
 
 
 
    /* Check if we have an illegal instruction */
    /* Check if we have an illegal instruction */
    if(insn_index == -1) {
    if(insn_index == -1) {
      gen_l_invalid(opq, param_t, param, delay_insn);
    gen_l_invalid(opq, NULL, NULL, delay_insn);
      if(delay_insn) {
    return;
        /* There is no need to do any jump handleing stuff as the instruction
 
         * will generate an exception */
 
        if(opq->prev->jump_local == 2) {
 
          opq->prev->xref->next = cpu_state.inf_xrefs;
 
          cpu_state.inf_xrefs = opq->prev->xref;
 
        }
 
        opq->prev->jump_local = 0;
 
        delay_insn = 0;
 
      }
 
      continue;
 
    }
    }
 
 
 
  /* If we are recompileing an instruction that has a delay slot and is in the
 
   * delay slot, ignore it.  This is undefined behavour. */
 
  if(delay_insn && ((or32_opcodes[insn_index].func_unit == it_jump) ||
 
                    (or32_opcodes[insn_index].func_unit == it_branch)))
 
    return;
 
 
    /* figure out instruction operands */
    /* figure out instruction operands */
    for(j = 0; j < NUM_T_REGS; j++)
  for(i = 0; i < NUM_T_REGS; i++)
      pres_t[j] = 0;
    pres_t[i] = 0;
 
 
    param_t[0] = T_NONE;
    param_t[0] = T_NONE;
    param_t[1] = T_NONE;
    param_t[1] = T_NONE;
    param_t[2] = T_NONE;
    param_t[2] = T_NONE;
    param_r[0] = 0;
    param_r[0] = 0;
Line 920... Line 746...
    while(1) {
    while(1) {
      param[param_num] = eval_operand_val(insn, opd);
      param[param_num] = eval_operand_val(insn, opd);
 
 
      if(opd->type & OPTYPE_REG) {
      if(opd->type & OPTYPE_REG) {
        /* check which temporary the register is in, if any */
        /* check which temporary the register is in, if any */
        for(j = 0; j < NUM_T_REGS; j++) {
      for(i = 0; i < NUM_T_REGS; i++) {
          if(reg_t[j] == param[param_num]) {
        if(opq->reg_t_d[i] == param[param_num]) {
            param_t[param_num] = j;
          param_t[param_num] = i;
            pres_t[j] = 1;
          pres_t[i] = 1;
          }
          }
        }
        }
      }
      }
 
 
      param_num++;
      param_num++;
Line 935... Line 761...
      if(opd->type & OPTYPE_LAST)
      if(opd->type & OPTYPE_LAST)
        break;
        break;
      opd++;
      opd++;
    }
    }
 
 
    opd = op_start[insn_index];
  /* Jump instructions are special since they have a delay slot and thus they
 
   * need to control the exact operation sequence.  Special case these, here to
 
   * avoid haveing loads of if(.func_unit != it_jump && != it_branch) below */
 
  if((or32_opcodes[insn_index].func_unit == it_jump) ||
 
     (or32_opcodes[insn_index].func_unit == it_branch)) {
 
    /* Ship the jump-to register out (if it exists).  It requires special
 
     * handleing, which is done in gen_j_reg. */
 
    for(i = 0; i < NUM_T_REGS; i++) {
 
      if(pres_t[i]) {
 
        gen_op_move_gpr_t[i][opq->reg_t_d[i]](opq->prev, 1);
 
        opq->reg_t_d[i] = 32;
 
        opq->reg_t[i] = 32;
 
      }
 
    }
 
 
 
    /* FIXME: Do this in a more elegent way */
 
    if(!strncmp(or32_opcodes[insn_index].name, "l.jal", 5)) {
 
      /* In the case of a l.jal instruction, make sure that LINK_REGNO is not in
 
       * a temporary.  The problem is that the l.jal(r) instruction stores the
 
       * `return address' in LINK_REGNO.  The temporaries are shiped out only
 
       * after the delay slot instruction has executed and so it overwrittes the
 
       * `return address'. */
 
      for(k = 0; k < NUM_T_REGS; k++) {
 
        if(opq->reg_t_d[k] == LINK_REGNO) {
 
          gen_op_move_gpr_t[k][LINK_REGNO](opq, 1);
 
          opq->reg_t_d[k] = 32;
 
          break;
 
        }
 
      }
 
    }
 
 
 
    /* Jump instructions don't have a disposition */
 
    or32_opcodes[insn_index].exec(opq, param_t, param, delay_insn);
 
 
 
    /* Analysis is done by the individual jump instructions */
 
    /* Jump instructions don't touch runtime.sim.mem_cycles */
 
    /* Jump instructions run their own scheduler */
 
    return;
 
  }
 
 
    /* Before an exception takes place, all registers must be stored. */
    /* Before an exception takes place, all registers must be stored. */
    if((or32_opcodes[insn_index].func_unit == it_exception)) {
    if((or32_opcodes[insn_index].func_unit == it_exception)) {
      if(opq->prev) {
      if(opq->prev) {
        ship_gprs_out_t(opq->prev, 1, reg_t);
      ship_gprs_out_t(opq->prev, 1, opq->reg_t_d);
        for(j = 0; j < NUM_T_REGS; j++) {
      for(i = 0; i < NUM_T_REGS; i++) {
          opq->prev->reg_t[j] = 32;
        opq->reg_t_d[i] = 32;
          reg_t[j] = 32;
        opq->reg_t[i] = 32;
        }
        }
      }
      }
    }
    }
 
 
 
  opd = op_start[insn_index];
 
 
    for(j = 0; j < param_num; j++, opd++) {
    for(j = 0; j < param_num; j++, opd++) {
      while(!(opd->type & OPTYPE_OP)) opd++;
      while(!(opd->type & OPTYPE_OP)) opd++;
      if(!(opd->type & OPTYPE_REG))
      if(!(opd->type & OPTYPE_REG))
        continue;
        continue;
 
 
Line 960... Line 826...
        continue;
        continue;
 
 
      /* Check if this register has been moved into a temporary in a previous
      /* Check if this register has been moved into a temporary in a previous
       * operand */
       * operand */
      for(k = 0; k < NUM_T_REGS; k++) {
      for(k = 0; k < NUM_T_REGS; k++) {
        if(reg_t[k] == param[j]) {
      if(opq->reg_t_d[k] == param[j]) {
          /* Yes, this register is already in a temporary */
          /* Yes, this register is already in a temporary */
 
        if(or32_opcodes[insn_index].func_unit != it_jump) {
          pres_t[k] = 1;
          pres_t[k] = 1;
          reg_t[k] = param[j];
 
          param_t[j] = k;
          param_t[j] = k;
 
        }
          break;
          break;
        }
        }
      }
      }
      if(k != NUM_T_REGS)
      if(k != NUM_T_REGS)
        continue;
        continue;
 
 
      if((param_t[j] != T_NONE))
    if(param_t[j] != T_NONE)
        continue;
        continue;
 
 
      /* Search for an unused temporary */
      /* Search for an unused temporary */
      k = find_unused_t(pres_t, reg_t);
    k = find_unused_t(pres_t, opq->reg_t_d);
      if(reg_t[k] < 32) {
    if(opq->reg_t_d[k] < 32) {
        gen_op_move_gpr_t[k][reg_t[k]](opq->prev, 1);
      /* FIXME: Only ship the temporary out if it has been used as a destination
 
       * register */
 
      gen_op_move_gpr_t[k][opq->reg_t_d[k]](opq->prev, 1);
        opq->reg_t[k] = 32;
        opq->reg_t[k] = 32;
 
      opq->reg_t_d[k] = 32;
      }
      }
      pres_t[k] = 1;
      pres_t[k] = 1;
      reg_t[k] = param[j];
    opq->reg_t_d[k] = param[j];
      param_t[j] = k;
      param_t[j] = k;
      /* FIXME: Only generate code to move the register into a temporary if it
      /* FIXME: Only generate code to move the register into a temporary if it
       *        is used as a source operand */
       *        is used as a source operand */
      gen_op_move_t_gpr[k][reg_t[k]](opq, 1);
    gen_op_move_t_gpr[k][opq->reg_t_d[k]](opq, 0);
    }
    }
 
 
    /* FIXME: Do this in a more elegent way */
 
    if(!strncmp(or32_opcodes[insn_index].name, "l.jal", 5)) {
 
      /* In the case of a l.jal instruction, make sure that LINK_REGNO is not in
 
       * a temporary.  The problem is that the l.jal(r) instruction stores the
 
       * `return address' in LINK_REGNO.  The temporaries are shiped out only
 
       * after the delay slot instruction has executed and so it overwrittes the
 
       * `return address'. */
 
      for(k = 0; k < NUM_T_REGS; k++) {
 
        if(reg_t[k] == LINK_REGNO) {
 
          gen_op_move_gpr_t[k][LINK_REGNO](opq, 1);
 
          reg_t[k] = 32;
 
          opq->reg_t[k] = 32;
 
          break;
 
        }
 
      }
 
    }
 
 
 
    /* Store the state of the temporaries into dyn->ts */
 
    dyn->ts[(rec_addr & (PAGE_LEN - 1)) / 2] = 0;
 
    if(reg_t[0] < 32)
 
      dyn->ts[(rec_addr & (PAGE_LEN - 1)) / 2] = reg_t[0];
 
    if(reg_t[1] < 32)
 
      dyn->ts[(rec_addr & (PAGE_LEN - 1)) / 2] |= reg_t[1] << 5;
 
    if(reg_t[2] < 32)
 
      dyn->ts[(rec_addr & (PAGE_LEN - 1)) / 2] |= reg_t[2] << 10;
 
 
 
    /* To get the execution log correct for instructions like l.lwz r4,0(r4) the
    /* To get the execution log correct for instructions like l.lwz r4,0(r4) the
     * effective address needs to be calculated before the instruction is
     * effective address needs to be calculated before the instruction is
     * simulated */
     * simulated */
    if(do_stats) {
    if(do_stats) {
      /* Find any disposition in the instruction */
      /* Find any disposition in the instruction */
Line 1034... Line 878...
      }
      }
    }
    }
 
 
    or32_opcodes[insn_index].exec(opq, param_t, param, delay_insn);
    or32_opcodes[insn_index].exec(opq, param_t, param, delay_insn);
 
 
    /* If any sort of analysis is done, store all temporaries and run
  if(or32_opcodes[insn_index].func_unit != it_exception) {
     * analysis() */
    if(do_stats)
    if(do_stats) {
 
      ship_gprs_out_t(opq, 1, reg_t);
 
      for(j = 0; j < NUM_T_REGS; j++)
 
        reg_t[j] = 32;
 
 
 
      gen_op_analysis(opq, 1, insn_index, insn);
      gen_op_analysis(opq, 1, insn_index, insn);
    }
    }
 
 
    /* The call to join_mem_cycles() could be put into the individual operations
    /* The call to join_mem_cycles() could be put into the individual operations
     * that emulate the load/store instructions, but then it would be added to
     * that emulate the load/store instructions, but then it would be added to
     * the cycle counter before analysis() is called, which not how the complex
   * the cycle counter before analysis() is called, which is not how the complex
     * execution modell does it. */
   * execution model does it. */
    if((or32_opcodes[insn_index].func_unit == it_load) ||
    if((or32_opcodes[insn_index].func_unit == it_load) ||
       (or32_opcodes[insn_index].func_unit == it_store))
       (or32_opcodes[insn_index].func_unit == it_store))
      gen_op_join_mem_cycles(opq, 1);
      gen_op_join_mem_cycles(opq, 1);
 
 
    /* If a delay sloted instruction is in the delay slot, avoid doing a jump on
  /* Delay slot instructions get a special scheduler, thus don't generate it
     * the first delay sloted instruction.  The problem with not doing the above
   * here */
     * is that the 0x00000000 instruction is a jump instruction, which is used
  if((or32_opcodes[insn_index].func_unit != it_exception) && !delay_insn)
     * for padding, and if there ends up being a jump instruction directly after
    gen_op_do_sched(opq, 1);
     * some padding and the code jumps to this location (as with the mmu test)
 
     * the jump instruction will set cpu_state.pc_delay but code will get
 
     * generated after the jump instruction and before the delay slot
 
     * instruciton to check cpu_state.pc_delay and jump out if it is set and so
 
     * we end up jumping out to the padding instruction.  With some thought, the
 
     * 0x00000000 opcode could really have been encoded to some arithmetic
 
     * operation that would end up nop-ing (or better yet, to the l.nop 0
 
     * instruction itself) */
 
    /* If we came up to a page local jump and because it is the delay slot of
 
     * another delay sloted instruction the case below is skipped and
 
     * opq->prev->jump_local will remain set to 1, fix this by reseting it now*/
 
    if(delay_insn && ((or32_opcodes[insn_index].func_unit == it_jump) ||
 
                      (or32_opcodes[insn_index].func_unit == it_branch))) {
 
      /* We don't generate code to do the relocation so there will be none.
 
       * Avoid haveing a reference to it */
 
      /* Also remove the cross reference to it */
 
      if(opq->prev) {
 
        if(opq->prev->jump_local == 2) {
 
          opq->prev->xref->next = cpu_state.inf_xrefs;
 
          cpu_state.inf_xrefs = opq->prev->xref;
 
        }
 
        opq->prev->jump_local = 0;
 
      }
 
      delay_insn = 0;
 
    }
 
 
 
    /* In the case of an instruction in the delay slot the pc must be updated
 
     * before op_do_sched runs because if it so happens to generate an exception
 
     * it will think that we are still executeing the delay slot instruction
 
     * which infact we have just executed and then SPR_EPCR_BASE will end up
 
     * pointing to the delay slot instruction, which is wrong.  If the delay
 
     * slot instruction is an exception instruction (l.trap/l.sys) the exception
 
     * must appear to have been generated in the delay slot */
 
    if(delay_insn && (or32_opcodes[insn_index].func_unit != it_exception)) {
 
      if(xref || (delay_insn_type == it_branch))
 
        gen_op_set_pc_preemt_check(opq, 1);
 
      else /* delay_insn_tyte == it_jump */
 
        gen_op_set_pc_preemt(opq, 1);
 
      /* Move temporaries to their permanent storage */
 
      ship_gprs_out_t(opq, 1, reg_t);
 
    }
 
 
 
    /* Same reason as for the above case */
 
    if(or32_opcodes[insn_index].func_unit == it_exception) {
 
      /* FIXME: Do the instruction switch below in a more elegent way */
 
      if(!strcmp(or32_opcodes[insn_index].name, "l.rfe")) {
 
        gen_op_set_rfe_pc(opq, 1);
 
      } else if(!strcmp(or32_opcodes[insn_index].name, "l.sys")) {
 
        gen_op_set_except_pc(opq, 1, EXCEPT_SYSCALL - 4);
 
      } else { /* or32_opcodes[insn_index].name == "l.trap" */
 
        gen_op_set_except_pc(opq, 1, EXCEPT_TRAP - 4);
 
      }
 
      gen_op_set_ts_current(opq, 1);
 
    }
    }
 
 
    gen_op_do_sched(opq, 1);
/* rec_page is a physical address */
 
void recompile_page(struct dyn_page *dyn)
 
{
 
  unsigned int j;
 
  struct op_queue *opq = cpu_state.opqs;
 
  oraddr_t rec_addr = dyn->or_page;
 
  oraddr_t rec_page = dyn->or_page;
 
  void **loc;
 
 
    /* If this is an exception instruction then we still need to perform the
  /* The start of the next page */
     * exception */
  rec_page += PAGE_LEN;
    if(or32_opcodes[insn_index].func_unit == it_exception) {
 
      /* FIXME: Do the instruction switch below in a more elegent way */
 
      if(!strcmp(or32_opcodes[insn_index].name, "l.rfe")) {
 
        gen_op_rfe(opq, 1);
 
      } else if(!strcmp(or32_opcodes[insn_index].name, "l.sys")) {
 
        gen_op_do_except(opq, 1, EXCEPT_SYSCALL);
 
      } else { /* or32_opcodes[insn_index].name == "l.trap" */
 
        gen_op_do_except(opq, 1, EXCEPT_TRAP);
 
      }
 
    }
 
 
 
    /* FIXME: If the delay slot is cross referenced after we have stuck the jump
  printf("Recompileing page %"PRIxADDR"\n", rec_addr);
     * instruction in the operations queue we will genererate temporary->
  fflush(stdout);
     * register code after the jump, which will be unreachable.  This is no
 
     * problem as all temporaries are stored in anticipation for a jump. */
  /* Mark all temporaries as not containing a register */
    /* FIXME: If the delay slot is cross referenced we should generate the
 
     * conditional jump code as we do below.  This will not happen if the delay
 
     * slot is cross referenced after we generate the operations for the jump */
 
    /* FIXME: If the instruction in the delay slot is an exception instruction
 
     * the code that we generate below will be unreachable since the exception
 
     * instruction jumps to the exection vector */
 
    /* Generate code to jump out to the proper location */
 
    if(delay_insn) {
 
      for(j = 0; j < NUM_T_REGS; j++)
      for(j = 0; j < NUM_T_REGS; j++)
        reg_t[j] = 32;
    opq->reg_t[j] = 32; /* Out-of-range registers */
 
 
      if(xref || (delay_insn_type == it_branch)) {
  dyn->delayr = -verify_memoryarea(rec_addr)->delayr;
        /* If the delay-slot instruction is cross referenced, then we have to
 
         * check env->delay_insn */
  opq->num_ops = 0;
        if(opq->prev && opq->prev->jump_local) {
  opq->num_ops_param = 0;
          gen_op_jmp_imm_check(opq, 1, 0);
 
          opq->prev->jump_local_loc = &opq->ops_param[opq->num_ops_param - 1];
  /* Insert code to check if the first instruction is exeucted in a delay slot*/
        } else {
  gen_op_check_delay_slot(opq, 1, 0);
          gen_op_do_jump_check(opq, 1);
  recompile_insn(opq, rec_addr, 1);
        }
  ship_gprs_out_t(opq, 1, opq->reg_t_d);
      } else if(delay_insn_type == it_jump) {
  gen_op_do_sched_delay(opq, 1);
        gen_op_clear_delay_insn(opq, 1);
        gen_op_clear_delay_insn(opq, 1);
        if(opq->prev && opq->prev->jump_local) {
  gen_op_do_jump_delay(opq, 1);
          /* The 0 will get patched when the page-local jumps get patched */
  gen_op_mark_loc(opq, 1);
          gen_op_jmp_imm(opq, 1, 0);
 
          /* FIXME: opq->ops_param is realloced with realloc and so we risk a
 
           * reallocation in which the location ends up moveing in memory */
 
          opq->prev->jump_local_loc = &opq->ops_param[opq->num_ops_param - 1];
 
        } else {
 
          gen_op_do_jump(opq, 1);
 
        }
 
      }
 
      delay_insn = 0;
 
    }
 
 
 
    /* Set flag for next instruction to be in a delay slot */
  for(j = 0; j < NUM_T_REGS; j++)
    if((or32_opcodes[insn_index].func_unit == it_jump) ||
    opq->reg_t[j] = 32; /* Out-of-range registers */
       (or32_opcodes[insn_index].func_unit == it_branch)) {
 
      delay_insn = 1;
  for(; rec_addr < rec_page; rec_addr += 4, opq = opq->next) {
      delay_insn_type = or32_opcodes[insn_index].func_unit;
    if(opq->prev) {
    }
      opq->num_ops = 0;
 
      opq->num_ops_param = 0;
  }
  }
 
    opq->jump_local = -1;
 
    opq->not_jump_loc = -1;
 
 
 
    opq->insn_addr = rec_addr;
 
 
 
    /* Check if this location is cross referenced */
 
    if(opq->xref) {
 
      /* If the current address is cross-referenced, the temporaries shall be
 
       * in an undefined state, so we must assume that no registers reside in
 
       * them */
 
      /* Ship out the current set of registers from the temporaries */
 
      if(opq->prev)
 
        ship_gprs_out_t(opq->prev, 1, opq->reg_t);
 
 
  if(delay_insn) {
      for(j = 0; j < NUM_T_REGS; j++)
    dyn->carrys_delay_slot = 1;
        opq->reg_t[j] = 32;
    /* Quick hack to avoid dereferencing an uninitialised pointer below with
 
     * *opq->jump_local_loc */
 
    if(opq->prev->jump_local == 2) {
 
      /* FIXME: In this case the delay slot instruction won't get executed */
 
      opq->prev->xref->next = cpu_state.inf_xrefs;
 
      cpu_state.inf_xrefs = opq->prev->xref;
 
    }
    }
    opq->prev->jump_local = 0;
 
 
    recompile_insn(opq, rec_addr, 0);
 
 
 
    /* Store the state of the temporaries */
 
    memcpy(opq->next->reg_t, opq->reg_t_d, sizeof(opq->reg_t));
  }
  }
 
 
  dyn->dirty = 0;
  dyn->dirty = 0;
 
 
 
  /* Store the state of the temporaries */
 
  dyn->ts_bound[PAGE_LEN >> 2] = dyn->ts_during[j];
 
 
  /* Ship temporaries out to the corrisponding registers */
  /* Ship temporaries out to the corrisponding registers */
  ship_gprs_out_t(opq->prev, 1, reg_t);
  ship_gprs_out_t(opq->prev, 1, opq->reg_t);
 
 
  opq->num_ops = 0;
  opq->num_ops = 0;
  opq->num_ops_param = 0;
  opq->num_ops_param = 0;
  opq->jump_local = 0;
  opq->not_jump_loc = -1;
 
  opq->jump_local = -1;
 
 
  /* Insert code to jump to the next page */
  /* Insert code to jump to the next page */
  gen_op_set_ts_current(opq, 1);
  gen_op_set_ts_current(opq, 1);
  gen_op_do_jump_pc(opq, 1);
  gen_op_do_jump(opq, 1);
 
 
  /* Generate the code */
  /* Generate the code */
  gen_code(cpu_state.opqs, dyn);
  gen_code(cpu_state.opqs, dyn);
 
 
  /* Patch the x-ref table */
  /* Fix up the locations */
  for(xref = dyn->xrefs; xref; xref = xref->next)
  for(loc = dyn->locs; loc < &dyn->locs[PAGE_LEN / 4]; loc++)
    xref->dyn_addr = dyn->host_page + (unsigned int)xref->dyn_addr;
    *loc += (unsigned int)dyn->host_page;
 
 
 
  cpu_state.opqs->ops_param[0] += (unsigned int)dyn->host_page;
 
 
  /* Search for page-local jumps */
  /* Search for page-local jumps */
  for(opq = cpu_state.opqs; opq; opq = opq->next) {
  for(opq = cpu_state.opqs, j = 0; j < (PAGE_LEN / 4); opq = opq->next, j++) {
    if(opq->jump_local) {
    if(opq->jump_local != -1)
      if(opq->jump_local == 2)
      opq->ops_param[opq->jump_local] =
        /* This cross reference was not patched above so patch it now */
                              (unsigned int)dyn->locs[opq->jump_local_loc >> 2];
        opq->xref->dyn_addr = dyn->host_page + (unsigned int)opq->xref->dyn_addr;
 
 
    if(opq->not_jump_loc != -1)
      *opq->jump_local_loc = (unsigned int)opq->xref->dyn_addr;
      opq->ops_param[opq->not_jump_loc] = (unsigned int)dyn->locs[j + 1];
      if(opq->jump_local == 2) {
 
        /* Return the xref to the pool of infinite loop cross references */
    /* Store the state of the temporaries into dyn->ts_bound */
        opq->xref->next = cpu_state.inf_xrefs;
    dyn->ts_bound[j] = 0;
        cpu_state.inf_xrefs = opq->xref;
    if(opq->reg_t[0] < 32)
      }
      dyn->ts_bound[j] = opq->reg_t[0];
    }
    if(opq->reg_t[1] < 32)
 
      dyn->ts_bound[j] |= opq->reg_t[1] << 5;
 
    if(opq->reg_t[2] < 32)
 
      dyn->ts_bound[j] |= opq->reg_t[2] << 10;
 
 
 
    dyn->ts_during[j] = 0;
 
    if(opq->reg_t_d[0] < 32)
 
      dyn->ts_during[j] = opq->reg_t_d[0];
 
    if(opq->reg_t_d[1] < 32)
 
      dyn->ts_during[j] |= opq->reg_t_d[1] << 5;
 
    if(opq->reg_t_d[2] < 32)
 
      dyn->ts_during[j] |= opq->reg_t_d[2] << 10;
  }
  }
 
 
  /* Patch the relocations */
  /* Patch the relocations */
  patch_relocs(cpu_state.opqs, dyn->host_page);
  patch_relocs(cpu_state.opqs, dyn->host_page);
 
 
  /* FIXME: Fix the issue below in a more elegent way */
  /* FIXME: Fix the issue below in a more elegent way */
  /* Since eval_insn is called to get the instruction, runtime.sim.mem_cycles is
  /* Since eval_insn is called to get the instruction, runtime.sim.mem_cycles is
   * updated but the recompiler expectes it to start a 0, so reset it */
   * updated but the recompiler expectes it to start a 0, so reset it */
  runtime.sim.mem_cycles = 0;
  runtime.sim.mem_cycles = 0;
 
 
#if 0
 
  This is very usefull during debuging
 
  /* Count the number of infinite loop cross references (to make sure that we
 
   * returned them all) */
 
  for(j = 0, xref = cpu_state.inf_xrefs; xref; xref = xref->next) {
 
    printf("Cross reference to %"PRIxADDR" is here\n", xref->or_addr);
 
    j++;
 
  }
 
 
 
  if(j != (PAGE_LEN / 4)) {
 
    fprintf(stderr, "Infinite loop cross references are leaked!\n");
 
    fprintf(stderr, "Number in free list now: %i, meant to be: %i\n", j, PAGE_LEN / 4);
 
    exit(1);
 
  }
 
#endif
 
 
 
}
 
 
 
struct x_ref *add_to_xrefs(struct dyn_page *dp, oraddr_t addr)
 
{
 
  struct x_ref *new;
 
  struct x_ref *cur;
 
  struct x_ref *prev;
 
 
 
  new = malloc(sizeof(struct x_ref));
 
 
 
  new->ref = 1;
 
  new->or_addr = addr;
 
 
 
  /* Find the location to insert the address */
 
  for(cur = dp->xrefs, prev = NULL; cur; prev = cur, cur = cur->next) {
 
    if(cur->or_addr > addr)
 
      break;
 
  }
 
 
 
  if(prev)
 
    prev->next = new;
 
  else
 
    dp->xrefs = new;
 
  new->next = cur;
 
 
 
  return new;
 
}
}
 
 
/* Returns non-zero if the jump is into this page, 0 otherwise */
/* Returns non-zero if the jump is into this page, 0 otherwise */
static int find_jump_loc(oraddr_t j_ea, struct op_queue *opq)
static int find_jump_loc(oraddr_t j_ea, struct op_queue *opq)
{
{
  struct dyn_page *dp;
 
  int i;
  int i;
  struct x_ref *xref = NULL;
 
  int *ops;
 
 
 
  /* Mark the jump as non page local if the delay slot instruction is on the
  /* Mark the jump as non page local if the delay slot instruction is on the
   * next page to the jump instruction.  This should not be needed */
   * next page to the jump instruction.  This should not be needed */
  if((ADDR_PAGE(j_ea) != ADDR_PAGE(opq->insn_addr)) ||
  if((ADDR_PAGE(j_ea) != ADDR_PAGE(opq->insn_addr)) ||
     (ADDR_PAGE(opq->insn_addr) != ADDR_PAGE(opq->insn_addr + 4)))
     (ADDR_PAGE(opq->insn_addr) != ADDR_PAGE(opq->insn_addr + 4)))
Line 1292... Line 1040...
     * page */
     * page */
    return 0;
    return 0;
 
 
  /* The jump is into the page currently undergoing dynamic recompilation */
  /* The jump is into the page currently undergoing dynamic recompilation */
 
 
  /* FIXME: It would be great if we didn't have to do this (find_dynd...) (it is
 
   *        already passed to recompile_page) */
 
  dp = find_dynd_page(j_ea);
 
 
 
  /* Check if we have already x-refed this location */
 
  if((xref = find_host_x_ref(dp->xrefs, j_ea))) {
 
    /* If we have already x-refed this location, don't x-ref it again */
 
    if(!find_held_x_ref(dp->held_xrefs, j_ea)) {
 
      xref->ref++;
 
      add_to_held_xrefs(dp, xref);
 
    }
 
  } else {
 
    /* Stick this address into the page's x-ref table */
 
    xref = add_to_xrefs(dp, j_ea);
 
    add_to_held_xrefs(dp, xref);
 
  }
 
 
 
  opq->xref = xref;
 
 
 
  /* If we haven't got to the location of the jump, everything is ok */
  /* If we haven't got to the location of the jump, everything is ok */
  if(j_ea > opq->insn_addr)
  if(j_ea > opq->insn_addr) {
 
    /* Find the corissponding opq and mark it as cross referenced */
 
    for(i = (j_ea - opq->insn_addr) / 4; i; i--)
 
      opq = opq->next;
 
    opq->xref = 1;
    return 1;
    return 1;
 
  }
 
 
  /* Insert temporary -> register code before the jump ea and register ->
  /* Insert temporary -> register code before the jump ea and register ->
   * temporary at the x-ref address */
   * temporary at the x-ref address */
  while(opq->insn_addr > j_ea) opq = opq->prev;
  for(i = (opq->insn_addr - j_ea) / 4; i; i--)
 
    opq = opq->prev;
 
 
  if(!opq->prev)
  if(!opq->prev)
    /* We're at the begining of a page, no need to do anything */
    /* We're at the begining of a page, no need to do anything */
    return 1;
    return 1;
 
 
  /* Found location, insert code */
  /* Found location, insert code */
 
 
  ship_gprs_out_t(opq->prev, 1, opq->reg_t);
  ship_gprs_out_t(opq->prev, 1, opq->reg_t);
 
 
  for(i = 0; i < NUM_T_REGS; i++) {
  for(i = 0; i < NUM_T_REGS; i++) {
    if(opq->reg_t[i] < 32) {
    if(opq->reg_t[i] < 32) {
      gen_op_move_t_gpr[i][opq->reg_t[i]](opq, 0);
      gen_op_move_t_gpr[i][opq->reg_t[i]](opq, 0);
      opq->reg_t[i] = 32;
      opq->reg_t[i] = 32;
    }
    }
  }
  }
 
 
  /* In the event of a page local jump that jumps backwards (l.j -4) the cross
  opq->xref = 1;
   * reference to the target may not have existed when the jump-ed to adress was
 
   * recompiled and if the jump-ed to address is in the delay slot of another
 
   * jump instruction an op_jmp_imm_check operation must be generated and not an
 
   * op_jmp_imm operation */
 
  for(ops = opq->ops, i = 0; i < opq->num_ops; i++, ops++) {
 
    if(*ops == op_jmp_imm_indx)
 
      *ops = op_jmp_imm_check_indx;
 
    else if(*ops == op_set_pc_preemt_indx)
 
      *ops = op_set_pc_preemt_check_indx;
 
  }
 
 
 
  return 1;
  return 1;
}
}
 
 
 
static void gen_j_imm(struct op_queue *opq, oraddr_t off)
 
{
 
  int jump_local;
 
  int i;
 
  int reg_t[NUM_T_REGS];
 
 
 
  off <<= 2;
 
 
 
  jump_local = find_jump_loc(opq->insn_addr + off, opq);
 
 
 
  if(ADDR_PAGE(opq->insn_addr) != ADDR_PAGE(opq->insn_addr + 4)) {
 
    gen_op_set_pc_delay_imm(opq, 1, off);
 
    gen_op_do_sched(opq, 1);
 
    return;
 
  }
 
 
 
  gen_op_set_delay_insn(opq, 1);
 
  gen_op_do_sched(opq, 1);
 
 
 
  /* Recompileing the delay slot instruction must see the temoraries being in
 
   * the state after the jump/branch instruction not before */
 
  memcpy(reg_t, opq->reg_t, sizeof(reg_t));
 
  memcpy(opq->reg_t, opq->reg_t_d, sizeof(reg_t));
 
 
 
  /* Generate the delay slot instruction */
 
  recompile_insn(opq, opq->insn_addr + 4, 1);
 
 
 
  memcpy(opq->reg_t, reg_t, sizeof(reg_t));
 
 
 
  ship_gprs_out_t(opq, 1, opq->reg_t_d);
 
 
 
  gen_op_add_pc(opq, 1, (orreg_t)off - 8);
 
  gen_op_clear_delay_insn(opq, 1);
 
  gen_op_do_sched_delay(opq, 1);
 
 
 
  if(jump_local) {
 
    gen_op_jmp_imm(opq, 1, 0);
 
    opq->jump_local = opq->num_ops_param - 1;
 
    opq->jump_local_loc = (opq->insn_addr + (orreg_t)off) & (PAGE_LEN - 1);
 
  } else
 
    gen_op_do_jump(opq, 1);
 
}
 
 
 
static const generic_gen_op set_pc_delay_gpr[32] = {
 
 NULL,
 
 gen_op_move_gpr1_pc_delay,
 
 gen_op_move_gpr2_pc_delay,
 
 gen_op_move_gpr3_pc_delay,
 
 gen_op_move_gpr4_pc_delay,
 
 gen_op_move_gpr5_pc_delay,
 
 gen_op_move_gpr6_pc_delay,
 
 gen_op_move_gpr7_pc_delay,
 
 gen_op_move_gpr8_pc_delay,
 
 gen_op_move_gpr9_pc_delay,
 
 gen_op_move_gpr10_pc_delay,
 
 gen_op_move_gpr11_pc_delay,
 
 gen_op_move_gpr12_pc_delay,
 
 gen_op_move_gpr13_pc_delay,
 
 gen_op_move_gpr14_pc_delay,
 
 gen_op_move_gpr15_pc_delay,
 
 gen_op_move_gpr16_pc_delay,
 
 gen_op_move_gpr17_pc_delay,
 
 gen_op_move_gpr18_pc_delay,
 
 gen_op_move_gpr19_pc_delay,
 
 gen_op_move_gpr20_pc_delay,
 
 gen_op_move_gpr21_pc_delay,
 
 gen_op_move_gpr22_pc_delay,
 
 gen_op_move_gpr23_pc_delay,
 
 gen_op_move_gpr24_pc_delay,
 
 gen_op_move_gpr25_pc_delay,
 
 gen_op_move_gpr26_pc_delay,
 
 gen_op_move_gpr27_pc_delay,
 
 gen_op_move_gpr28_pc_delay,
 
 gen_op_move_gpr29_pc_delay,
 
 gen_op_move_gpr30_pc_delay,
 
 gen_op_move_gpr31_pc_delay };
 
 
 
static void gen_j_reg(struct op_queue *opq, unsigned int gpr, int insn_index,
 
                      uint32_t insn)
 
{
 
  int i;
 
  int reg_t[NUM_T_REGS];
 
 
 
  if(do_stats)
 
    gen_op_analysis(opq, 1, insn_index, insn);
 
 
 
  if(!gpr)
 
    gen_op_clear_pc_delay(opq, 1);
 
  else
 
    set_pc_delay_gpr[gpr](opq, 1);
 
 
 
  gen_op_do_sched(opq, 1);
 
 
 
  /* Recompileing the delay slot instruction must see the temoraries being in
 
   * the state after the jump/branch instruction not before */
 
  memcpy(reg_t, opq->reg_t, sizeof(reg_t));
 
  memcpy(opq->reg_t, opq->reg_t_d, sizeof(reg_t));
 
 
 
  /* Generate the delay slot instruction */
 
  gen_op_set_delay_insn(opq, 1);
 
  recompile_insn(opq, opq->insn_addr + 4, 1);
 
 
 
  memcpy(opq->reg_t, reg_t, sizeof(reg_t));
 
 
 
  ship_gprs_out_t(opq, 1, opq->reg_t_d);
 
 
 
  gen_op_set_pc_pc_delay(opq, 1);
 
  gen_op_clear_delay_insn(opq, 1);
 
  gen_op_do_sched_delay(opq, 1);
 
 
 
  gen_op_do_jump_delay(opq, 1);
 
}
 
 
/*------------------------------[ Operation generation for an instruction ]---*/
/*------------------------------[ Operation generation for an instruction ]---*/
/* FIXME: Flag setting is not done in any instruction */
/* FIXME: Flag setting is not done in any instruction */
/* FIXME: Since r0 is not moved into a temporary, check all arguments below! */
/* FIXME: Since r0 is not moved into a temporary, check all arguments below! */
 
 
static const generic_gen_op clear_t[NUM_T_REGS] =
static const generic_gen_op clear_t[NUM_T_REGS] =
Line 1491... Line 1331...
}
}
 
 
void gen_l_bf(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_bf(struct op_queue *opq, int param_t[3], orreg_t param[3],
              int delay_slot)
              int delay_slot)
{
{
  opq->jump_local = find_jump_loc(opq->insn_addr + (orreg_t)(param[0] << 2), opq);
  int i;
  gen_op_check_flag(opq, 1, param[0] << 2);
  if(do_stats)
 
    gen_op_analysis(opq, 1, 3, 0x10000000 | (param[0] & 0x03ffffff));
 
 
 
  /* The temporaries are expected to be shiped out after the execution of the
 
   * branch instruction wether it branched or not */
 
  if(opq->prev) {
 
    ship_gprs_out_t(opq->prev, 1, opq->reg_t);
 
    for(i = 0; i < NUM_T_REGS; i++) {
 
      opq->reg_t[i] = 32;
 
      opq->reg_t_d[i] = 32;
 
    }
 
  }
 
 
 
  if(ADDR_PAGE(opq->insn_addr) != ADDR_PAGE(opq->insn_addr + 4)) {
 
    gen_op_check_flag_delay(opq, 1, param[0] << 2);
 
    gen_op_do_sched(opq, 1);
 
    opq->not_jump_loc = -1;
 
    return;
 
  }
 
 
 
  gen_op_check_flag(opq, 1, 0);
 
  opq->not_jump_loc = opq->num_ops_param - 1;
 
 
 
  gen_j_imm(opq, param[0]);
}
}
 
 
void gen_l_bnf(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_bnf(struct op_queue *opq, int param_t[3], orreg_t param[3],
               int delay_slot)
               int delay_slot)
{
{
  opq->jump_local = find_jump_loc(opq->insn_addr + (orreg_t)(param[0] << 2), opq);
  int i;
  gen_op_check_not_flag(opq, 1, param[0] << 2);
  if(do_stats)
 
    gen_op_analysis(opq, 1, 2, 0x0c000000 | (param[0] & 0x03ffffff));
 
 
 
  /* The temporaries are expected to be shiped out after the execution of the
 
   * branch instruction wether it branched or not */
 
  if(opq->prev) {
 
    ship_gprs_out_t(opq->prev, 1, opq->reg_t);
 
    for(i = 0; i < NUM_T_REGS; i++) {
 
      opq->reg_t[i] = 32;
 
      opq->reg_t_d[i] = 32;
 
    }
 
  }
 
 
 
  if(ADDR_PAGE(opq->insn_addr) != ADDR_PAGE(opq->insn_addr + 4)) {
 
    gen_op_check_not_flag_delay(opq, 1, param[0] << 2);
 
    gen_op_do_sched(opq, 1);
 
    opq->not_jump_loc = -1;
 
    return;
 
  }
 
 
 
  gen_op_check_not_flag(opq, 1, 0);
 
  opq->not_jump_loc = opq->num_ops_param - 1;
 
 
 
  gen_j_imm(opq, param[0]);
 
 
 
  /* The temporaries don't get shiped out if the branch is not taken */
 
  memcpy(opq->next->reg_t, opq->reg_t, sizeof(opq->reg_t));
}
}
 
 
static const generic_gen_op l_cmov_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = {
static const generic_gen_op l_cmov_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = {
/* param0 -> t0 */              {
/* param0 -> t0 */              {
/* param0 -> t0, param1 -> t0 */ { NULL, gen_op_cmov_t0_t0_t1, gen_op_cmov_t0_t0_t2 },
/* param0 -> t0, param1 -> t0 */ { NULL, gen_op_cmov_t0_t0_t1, gen_op_cmov_t0_t0_t2 },
Line 1607... Line 1496...
/* param0 -> t2, param1 -> t2 */ { gen_op_div_t2_t2_t0, gen_op_div_t2_t2_t1, gen_op_div_t2_t2_t2 } } };
/* param0 -> t2, param1 -> t2 */ { gen_op_div_t2_t2_t0, gen_op_div_t2_t2_t1, gen_op_div_t2_t2_t2 } } };
 
 
void gen_l_div(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_div(struct op_queue *opq, int param_t[3], orreg_t param[3],
               int delay_slot)
               int delay_slot)
{
{
  /* Cross reference this location, since an ILLEGAL exception may happen */
 
  find_jump_loc(opq->insn_addr, opq);
 
  if(!param[2]) {
  if(!param[2]) {
    /* There is no option.  This _will_ cause an illeagal exception */
    /* There is no option.  This _will_ cause an illeagal exception */
    if(!delay_slot)
    if(!delay_slot)
      gen_op_illegal(opq, 1);
      gen_op_illegal(opq, 1);
    else
    else
Line 1652... Line 1539...
/* param0 -> t2, param1 -> t2 */ { gen_op_divu_t2_t2_t0, gen_op_divu_t2_t2_t1, gen_op_divu_t2_t2_t2 } } };
/* param0 -> t2, param1 -> t2 */ { gen_op_divu_t2_t2_t0, gen_op_divu_t2_t2_t1, gen_op_divu_t2_t2_t2 } } };
 
 
void gen_l_divu(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_divu(struct op_queue *opq, int param_t[3], orreg_t param[3],
                int delay_slot)
                int delay_slot)
{
{
  /* Cross reference this location, since an ILLEGAL exception may happen */
 
  find_jump_loc(opq->insn_addr, opq);
 
  if(!param[2]) {
  if(!param[2]) {
    /* There is no option.  This _will_ cause an illeagal exception */
    /* There is no option.  This _will_ cause an illeagal exception */
    if(!delay_slot)
    if(!delay_slot)
      gen_op_illegal(opq, 1);
      gen_op_illegal(opq, 1);
    else
    else
Line 1814... Line 1699...
}
}
 
 
void gen_l_j(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_j(struct op_queue *opq, int param_t[3], orreg_t param[3],
             int delay_slot)
             int delay_slot)
{
{
  gen_op_set_pc_delay_imm(opq, 1, param[0] << 2);
  if(do_stats)
 
    gen_op_analysis(opq, 1, 0, param[0] & 0x03ffffff);
 
 
  /* Don't allocate a seporate x-ref structure for the infinite loop instruction
  gen_j_imm(opq, param[0]);
   * (l.j 0) */
 
  if(!param[0]) {
 
    opq->jump_local = 2;
 
    opq->xref = cpu_state.inf_xrefs;
 
    opq->xref->or_addr = opq->insn_addr;
 
    cpu_state.inf_xrefs = opq->xref->next;
 
    return;
 
  }
 
 
 
  opq->jump_local = find_jump_loc(opq->insn_addr + (orreg_t)(param[0] << 2), opq);
 
}
}
 
 
void gen_l_jal(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_jal(struct op_queue *opq, int param_t[3], orreg_t param[3],
               int delay_slot)
               int delay_slot)
{
{
  /* It is highly likely that the location that was jumped to will `return'.
 
   * Therefore, insert a cross reference at that address */
 
  find_jump_loc(opq->insn_addr + 8, opq);
 
 
 
  gen_l_j(opq, param_t, param, delay_slot);
 
 
 
  /* Store the return address */
  /* Store the return address */
  gen_op_store_link_addr_gpr(opq, 1);
  gen_op_store_link_addr_gpr(opq, 1);
}
 
 
 
static const generic_gen_op set_pc_delay_t[NUM_T_REGS] =
  if(do_stats)
 { gen_op_set_pc_delay_t0, gen_op_set_pc_delay_t1, gen_op_set_pc_delay_t2 };
    gen_op_analysis(opq, 1, 1, 0x04000000 | (param[0] & 0x03ffffff));
 
 
 
  gen_j_imm(opq, param[0]);
 
}
 
 
void gen_l_jr(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_jr(struct op_queue *opq, int param_t[3], orreg_t param[3],
              int delay_slot)
              int delay_slot)
{
{
  /* Treat all jumps as non page-local */
  gen_j_reg(opq, param[0], 104, 0x14000000 | (param[0] << 11));
  opq->jump_local = 0;
 
 
 
  if(!param[0]) {
 
    gen_op_clear_pc_delay(opq, 1);
 
    return;
 
  }
 
 
 
  set_pc_delay_t[param_t[0]](opq, 1);
 
}
}
 
 
void gen_l_jalr(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_jalr(struct op_queue *opq, int param_t[3], orreg_t param[3],
                int delay_slot)
                int delay_slot)
{
{
  /* It is highly likely that the location that was jumped to will `return'.
 
   * Therefore, insert a cross reference at that address */
 
  find_jump_loc(opq->insn_addr + 8, opq);
 
 
 
  gen_l_jr(opq, param_t, param, delay_slot);
 
 
 
  /* Store the return address */
  /* Store the return address */
  gen_op_store_link_addr_gpr(opq, 1);
  gen_op_store_link_addr_gpr(opq, 1);
 
 
 
  gen_j_reg(opq, param[0], 105, 0x18000000 | (param[0] << 11));
}
}
 
 
/* FIXME: Optimise all load instruction when the disposition == 0 */
/* FIXME: Optimise all load instruction when the disposition == 0 */
 
 
static const imm_gen_op l_lbs_imm_t_table[NUM_T_REGS] =
static const imm_gen_op l_lbs_imm_t_table[NUM_T_REGS] =
Line 2293... Line 2153...
}
}
 
 
void gen_l_rfe(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_rfe(struct op_queue *opq, int param_t[3], orreg_t param[3],
               int delay_slot)
               int delay_slot)
{
{
 
  if(do_stats)
 
    gen_op_analysis(opq, 1, 12, 0x24000000);
 
 
  gen_op_prep_rfe(opq, 1);
  gen_op_prep_rfe(opq, 1);
 
  gen_op_do_sched(opq, 1);
 
  gen_op_do_jump(opq, 1);
}
}
 
 
/* FIXME: All store instructions should be optimised when the disposition = 0 */
/* FIXME: All store instructions should be optimised when the disposition = 0 */
 
 
static const imm_gen_op l_sb_clear_table[NUM_T_REGS] =
static const imm_gen_op l_sb_clear_table[NUM_T_REGS] =
Line 2989... Line 2854...
 
 
/* FIXME: This will not work if the l.sys is in a delay slot */
/* FIXME: This will not work if the l.sys is in a delay slot */
void gen_l_sys(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_sys(struct op_queue *opq, int param_t[3], orreg_t param[3],
               int delay_slot)
               int delay_slot)
{
{
  /* Since we *know* that we *will* jump to the next instruction, insert an xref
  if(do_stats)
   * there */
    gen_op_analysis(opq, 1, 7, 0x20000000 | param[0]);
  find_jump_loc(opq->insn_addr + 4, opq);
 
 
 
  if(!delay_slot)
  if(!delay_slot)
    gen_op_prep_sys(opq, 1);
    gen_op_prep_sys(opq, 1);
  else
  else
    gen_op_prep_sys_delay(opq, 1);
    gen_op_prep_sys_delay(opq, 1);
 
 
 
  gen_op_do_sched(opq, 1);
 
  gen_op_do_jump(opq, 1);
}
}
 
 
/* FIXME: This will not work if the l.trap is in a delay slot */
/* FIXME: This will not work if the l.trap is in a delay slot */
void gen_l_trap(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_trap(struct op_queue *opq, int param_t[3], orreg_t param[3],
                int delay_slot)
                int delay_slot)
{
{
  /* Since we *know* that we *will* jump to the next instruction, insert an xref
  if(do_stats)
   * there */
    gen_op_analysis(opq, 1, 8, 0x22000000);
  find_jump_loc(opq->insn_addr + 4, opq);
 
 
 
  if(!delay_slot)
  if(!delay_slot)
    gen_op_prep_trap(opq, 1);
    gen_op_prep_trap(opq, 1);
  else
  else
    gen_op_prep_trap_delay(opq, 1);
    gen_op_prep_trap_delay(opq, 1);
Line 3068... Line 2934...
}
}
 
 
void gen_l_invalid(struct op_queue *opq, int param_t[3], orreg_t param[3],
void gen_l_invalid(struct op_queue *opq, int param_t[3], orreg_t param[3],
                   int delay_slot)
                   int delay_slot)
{
{
  /* The program running on openrisc may decide to patch this location, so
 
   * just cross reference this location just-in-case */
 
  find_jump_loc(opq->insn_addr, opq);
 
  if(!delay_slot)
  if(!delay_slot)
    gen_op_illegal(opq, 1);
    gen_op_illegal(opq, 1);
  else
  else
    gen_op_illegal_delay(opq, 1);
    gen_op_illegal_delay(opq, 1);
}
}

powered by: WebSVN 2.1.0

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