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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [cpu/] [or1k/] [sprs.c] - Diff between revs 436 and 508

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 436 Rev 508
/* sprs.c -- Simulation of OR1K special-purpose registers
/* sprs.c -- Simulation of OR1K special-purpose registers
 
 
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 2008 Embecosm Limited
   Copyright (C) 2008 Embecosm Limited
 
 
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
 
 
   This program is free software; you can redistribute it and/or modify it
   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
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 3 of the License, or (at your option)
   Software Foundation; either version 3 of the License, or (at your option)
   any later version.
   any later version.
 
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
   more details.
 
 
   You should have received a copy of the GNU General Public License along
   You should have received a copy of the GNU General Public License along
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
/* This program is commented throughout in a fashion suitable for processing
/* This program is commented throughout in a fashion suitable for processing
   with Doxygen. */
   with Doxygen. */
 
 
 
 
/* Autoconf and/or portability configuration */
/* Autoconf and/or portability configuration */
#include "config.h"
#include "config.h"
#include "port.h"
#include "port.h"
 
 
/* System includes */
/* System includes */
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <errno.h>
#include <errno.h>
 
 
/* Package includes */
/* Package includes */
#include "sprs.h"
#include "sprs.h"
#include "sim-config.h"
#include "sim-config.h"
#include "debug.h"
#include "debug.h"
#include "execute.h"
#include "execute.h"
#include "spr-defs.h"
#include "spr-defs.h"
#include "tick.h"
#include "tick.h"
#include "dcache-model.h"
#include "dcache-model.h"
#include "icache-model.h"
#include "icache-model.h"
#include "dmmu.h"
#include "dmmu.h"
#include "immu.h"
#include "immu.h"
#include "toplevel-support.h"
#include "toplevel-support.h"
#include "pic.h"
#include "pic.h"
 
 
 
 
DECLARE_DEBUG_CHANNEL(immu);
DECLARE_DEBUG_CHANNEL(immu);
 
 
/* Set a specific SPR with a value. */
/* Set a specific SPR with a value. */
void mtspr(uint16_t regno, const uorreg_t value)
void mtspr(uint16_t regno, const uorreg_t value)
{
{
  uorreg_t prev_val;
  uorreg_t prev_val;
 
 
  prev_val = cpu_state.sprs[regno];
  prev_val = cpu_state.sprs[regno];
  cpu_state.sprs[regno] = value;
  cpu_state.sprs[regno] = value;
 
 
  /* MM: Register hooks.  */
  /* MM: Register hooks.  */
  switch (regno) {
  switch (regno) {
  case SPR_TTCR:
  case SPR_TTCR:
    spr_write_ttcr (value);
    spr_write_ttcr (value);
    break;
    break;
  case SPR_TTMR:
  case SPR_TTMR:
    spr_write_ttmr (prev_val);
    spr_write_ttmr (prev_val);
    break;
    break;
  /* Data cache simulateing stuff */
  /* Data cache simulateing stuff */
  case SPR_DCBPR:
  case SPR_DCBPR:
    /* FIXME: This is not correct.  The arch. manual states: "Memory accesses
    /* FIXME: This is not correct.  The arch. manual states: "Memory accesses
     * are not recorded (Unlike load or store instructions) and cannot invoke
     * are not recorded (Unlike load or store instructions) and cannot invoke
     * any exception".  If the physical address is invalid a bus error will be
     * any exception".  If the physical address is invalid a bus error will be
     * generated.  Also if the effective address is not resident in the mmu
     * generated.  Also if the effective address is not resident in the mmu
     * the read will happen from address 0, which is naturally not correct. */
     * the read will happen from address 0, which is naturally not correct. */
    dc_simulate_read(peek_into_dtlb(value, 0, 1), value, 4);
    dc_simulate_read(peek_into_dtlb(value, 0, 1), value, 4);
    cpu_state.sprs[SPR_DCBPR] = 0;
    cpu_state.sprs[SPR_DCBPR] = 0;
    break;
    break;
  case SPR_DCBFR:
  case SPR_DCBFR:
    dc_inv(value);
    dc_inv(value);
    cpu_state.sprs[SPR_DCBFR] = -1;
    cpu_state.sprs[SPR_DCBFR] = -1;
    break;
    break;
  case SPR_DCBIR:
  case SPR_DCBIR:
    dc_inv(value);
    dc_inv(value);
    cpu_state.sprs[SPR_DCBIR] = 0;
    cpu_state.sprs[SPR_DCBIR] = 0;
    break;
    break;
  case SPR_DCBWR:
  case SPR_DCBWR:
    cpu_state.sprs[SPR_DCBWR] = 0;
    cpu_state.sprs[SPR_DCBWR] = 0;
    break;
    break;
  case SPR_DCBLR:
  case SPR_DCBLR:
    cpu_state.sprs[SPR_DCBLR] = 0;
    cpu_state.sprs[SPR_DCBLR] = 0;
    break;
    break;
  /* Instruction cache simulateing stuff */
  /* Instruction cache simulateing stuff */
  case SPR_ICBPR:
  case SPR_ICBPR:
    /* FIXME: The arch manual does not say what happens when an invalid memory
    /* FIXME: The arch manual does not say what happens when an invalid memory
     * location is specified.  I guess the same as for the DCBPR register */
     * location is specified.  I guess the same as for the DCBPR register */
    ic_simulate_fetch(peek_into_itlb(value), value);
    ic_simulate_fetch(peek_into_itlb(value), value);
    cpu_state.sprs[SPR_ICBPR] = 0;
    cpu_state.sprs[SPR_ICBPR] = 0;
    break;
    break;
  case SPR_ICBIR:
  case SPR_ICBIR:
    ic_inv(value);
    ic_inv(value);
    cpu_state.sprs[SPR_ICBIR] = 0;
    cpu_state.sprs[SPR_ICBIR] = 0;
    break;
    break;
  case SPR_ICBLR:
  case SPR_ICBLR:
    cpu_state.sprs[SPR_ICBLR] = 0;
    cpu_state.sprs[SPR_ICBLR] = 0;
    break;
    break;
  case SPR_SR:
  case SPR_SR:
    cpu_state.sprs[regno] |= SPR_SR_FO;
    cpu_state.sprs[regno] |= SPR_SR_FO;
    if((value & SPR_SR_IEE) && !(prev_val & SPR_SR_IEE))
    if((value & SPR_SR_IEE) && !(prev_val & SPR_SR_IEE))
      pic_ints_en();
      pic_ints_en();
#if DYNAMIC_EXECUTION
#if DYNAMIC_EXECUTION
    if((value & SPR_SR_IME) && !(prev_val & SPR_SR_IME)) {
    if((value & SPR_SR_IME) && !(prev_val & SPR_SR_IME)) {
      TRACE_(immu)("IMMU just became enabled (%lli).\n", runtime.sim.cycles);
      TRACE_(immu)("IMMU just became enabled (%lli).\n", runtime.sim.cycles);
      recheck_immu(IMMU_GOT_ENABLED);
      recheck_immu(IMMU_GOT_ENABLED);
    } else if(!(value & SPR_SR_IME) && (prev_val & SPR_SR_IME)) {
    } else if(!(value & SPR_SR_IME) && (prev_val & SPR_SR_IME)) {
      TRACE_(immu)("Remove counting of mmu hit delay with cycles (%lli)\n",
      TRACE_(immu)("Remove counting of mmu hit delay with cycles (%lli)\n",
                   runtime.sim.cycles);
                   runtime.sim.cycles);
      recheck_immu(IMMU_GOT_DISABLED);
      recheck_immu(IMMU_GOT_DISABLED);
    }
    }
#endif
#endif
    break;
    break;
  case SPR_NPC:
  case SPR_NPC:
    {
    {
      /* The debugger has redirected us to a new address */
      /* The debugger has redirected us to a new address */
      /* This is usually done to reissue an instruction
      /* This is usually done to reissue an instruction
         which just caused a breakpoint exception. */
         which just caused a breakpoint exception. */
 
 
      /* JPB patch. When GDB stepi, this may be used to set the PC to the
      /* JPB patch. When GDB stepi, this may be used to set the PC to the
         value it is already at. If this is the case, then we do nothing (in
         value it is already at. If this is the case, then we do nothing (in
         particular we do not trash a delayed branch) */
         particular we do not trash a delayed branch) */
 
 
      if (value != cpu_state.pc)
      if (value != cpu_state.pc)
        {
        {
          cpu_state.pc = value;
          cpu_state.pc = value;
 
 
          if(!value && config.sim.verbose)
          if(!value && config.sim.verbose)
            PRINTF("WARNING: PC just set to 0!\n");
            PRINTF("WARNING: PC just set to 0!\n");
 
 
          /* Clear any pending delay slot jumps also */
          /* Clear any pending delay slot jumps also */
          cpu_state.delay_insn = 0;
          cpu_state.delay_insn = 0;
          pcnext = value + 4;
          pcnext = value + 4;
 
 
          /* Further JPB patch. If the processor is stalled, then subsequent
          /* Further JPB patch. If the processor is stalled, then subsequent
             reads of the NPC should return 0 until the processor is
             reads of the NPC should return 0 until the processor is
             unstalled. If the processor is stalled, note that the NPC has
             unstalled. If the processor is stalled, note that the NPC has
             been updated while the processor was stalled. */
             been updated while the processor was stalled. */
 
 
          if (runtime.cpu.stalled)
          if (runtime.cpu.stalled)
            {
            {
              cpu_state.npc_not_valid = 1;
              cpu_state.npc_not_valid = 1;
            }
            }
        }
        }
    }
    }
    break;
    break;
  case SPR_PICSR:
  case SPR_PICSR:
    if(!config.pic.edge_trigger)
    if(!config.pic.edge_trigger)
      /* When configured with level triggered interrupts we clear PICSR in PIC
      /* When configured with level triggered interrupts we clear PICSR in PIC
         peripheral model when incoming IRQ goes low */
         peripheral model when incoming IRQ goes low */
      cpu_state.sprs[SPR_PICSR] = prev_val;
      cpu_state.sprs[SPR_PICSR] = prev_val;
    break;
    break;
  case SPR_PICMR:
  case SPR_PICMR:
    /* If we have non-maskable interrupts, then the bottom two bits are always
    /* If we have non-maskable interrupts, then the bottom two bits are always
       one. */
       one. */
    if (config.pic.use_nmi)
    if (config.pic.use_nmi)
      {
      {
        cpu_state.sprs[SPR_SR] |= 0x00000003;
        cpu_state.sprs[SPR_PICMR] |= 0x00000003;
      }
      }
 
 
    if(cpu_state.sprs[SPR_SR] & SPR_SR_IEE)
    if(cpu_state.sprs[SPR_SR] & SPR_SR_IEE)
      pic_ints_en();
      pic_ints_en();
    break;
    break;
  case SPR_PMR:
  case SPR_PMR:
    /* PMR[SDF] and PMR[DCGE] are ignored completely. */
    /* PMR[SDF] and PMR[DCGE] are ignored completely. */
    if (config.pm.enabled && (value & SPR_PMR_SUME)) {
    if (config.pm.enabled && (value & SPR_PMR_SUME)) {
      PRINTF ("SUSPEND: PMR[SUME] bit was set.\n");
      PRINTF ("SUSPEND: PMR[SUME] bit was set.\n");
      sim_done();
      sim_done();
    }
    }
    break;
    break;
  default:
  default:
    /* Mask reserved bits in DTLBMR and DTLBMR registers */
    /* Mask reserved bits in DTLBMR and DTLBMR registers */
    if ( (regno >= SPR_DTLBMR_BASE(0)) && (regno < SPR_DTLBTR_LAST(3))) {
    if ( (regno >= SPR_DTLBMR_BASE(0)) && (regno < SPR_DTLBTR_LAST(3))) {
      if((regno & 0xff) < 0x80)
      if((regno & 0xff) < 0x80)
        cpu_state.sprs[regno] = DADDR_PAGE(value) |
        cpu_state.sprs[regno] = DADDR_PAGE(value) |
                              (value & (SPR_DTLBMR_V | SPR_DTLBMR_PL1 | SPR_DTLBMR_CID | SPR_DTLBMR_LRU));
                              (value & (SPR_DTLBMR_V | SPR_DTLBMR_PL1 | SPR_DTLBMR_CID | SPR_DTLBMR_LRU));
      else
      else
        cpu_state.sprs[regno] = DADDR_PAGE(value) |
        cpu_state.sprs[regno] = DADDR_PAGE(value) |
                              (value & (SPR_DTLBTR_CC | SPR_DTLBTR_CI | SPR_DTLBTR_WBC | SPR_DTLBTR_WOM |
                              (value & (SPR_DTLBTR_CC | SPR_DTLBTR_CI | SPR_DTLBTR_WBC | SPR_DTLBTR_WOM |
                              SPR_DTLBTR_A | SPR_DTLBTR_D | SPR_DTLBTR_URE | SPR_DTLBTR_UWE | SPR_DTLBTR_SRE |
                              SPR_DTLBTR_A | SPR_DTLBTR_D | SPR_DTLBTR_URE | SPR_DTLBTR_UWE | SPR_DTLBTR_SRE |
                              SPR_DTLBTR_SWE));
                              SPR_DTLBTR_SWE));
    }
    }
 
 
    /* Mask reseved bits in ITLBMR and ITLBMR registers */
    /* Mask reseved bits in ITLBMR and ITLBMR registers */
    if ( (regno >= SPR_ITLBMR_BASE(0)) && (regno < SPR_ITLBTR_LAST(3))) {
    if ( (regno >= SPR_ITLBMR_BASE(0)) && (regno < SPR_ITLBTR_LAST(3))) {
      if((regno & 0xff) < 0x80)
      if((regno & 0xff) < 0x80)
        cpu_state.sprs[regno] = IADDR_PAGE(value) |
        cpu_state.sprs[regno] = IADDR_PAGE(value) |
                              (value & (SPR_ITLBMR_V | SPR_ITLBMR_PL1 | SPR_ITLBMR_CID | SPR_ITLBMR_LRU));
                              (value & (SPR_ITLBMR_V | SPR_ITLBMR_PL1 | SPR_ITLBMR_CID | SPR_ITLBMR_LRU));
      else
      else
        cpu_state.sprs[regno] = IADDR_PAGE(value) |
        cpu_state.sprs[regno] = IADDR_PAGE(value) |
                              (value & (SPR_ITLBTR_CC | SPR_ITLBTR_CI | SPR_ITLBTR_WBC | SPR_ITLBTR_WOM |
                              (value & (SPR_ITLBTR_CC | SPR_ITLBTR_CI | SPR_ITLBTR_WBC | SPR_ITLBTR_WOM |
                              SPR_ITLBTR_A | SPR_ITLBTR_D | SPR_ITLBTR_SXE | SPR_ITLBTR_UXE));
                              SPR_ITLBTR_A | SPR_ITLBTR_D | SPR_ITLBTR_SXE | SPR_ITLBTR_UXE));
 
 
#if DYNAMIC_EXECUTION
#if DYNAMIC_EXECUTION
      if(cpu_state.sprs[SPR_SR] & SPR_SR_IME) {
      if(cpu_state.sprs[SPR_SR] & SPR_SR_IME) {
        /* The immu got reconfigured.  Recheck if the current page in execution
        /* The immu got reconfigured.  Recheck if the current page in execution
         * is resident in the immu ways.  This check would be done during the
         * is resident in the immu ways.  This check would be done during the
         * instruction fetch but since the dynamic execution model does not do
         * instruction fetch but since the dynamic execution model does not do
         * instruction fetchs, do it now. */
         * instruction fetchs, do it now. */
        recheck_immu(0);
        recheck_immu(0);
      }
      }
#endif
#endif
    }
    }
 
 
    /* Links to GPRS */
    /* Links to GPRS */
    if(regno >= 0x0400 && regno < 0x0420) {
    if(regno >= 0x0400 && regno < 0x0420) {
      cpu_state.reg[regno - 0x0400] = value;
      cpu_state.reg[regno - 0x0400] = value;
    }
    }
    break;
    break;
  }
  }
}
}
 
 
/* Get a specific SPR. */
/* Get a specific SPR. */
uorreg_t mfspr(const uint16_t regno)
uorreg_t mfspr(const uint16_t regno)
{
{
  uorreg_t ret;
  uorreg_t ret;
 
 
  ret = cpu_state.sprs[regno];
  ret = cpu_state.sprs[regno];
 
 
  switch (regno) {
  switch (regno) {
  case SPR_NPC:
  case SPR_NPC:
 
 
    /* The NPC is the program counter UNLESS the NPC has been changed and we
    /* The NPC is the program counter UNLESS the NPC has been changed and we
       are stalled, which will have flushed the pipeline, so the value is
       are stalled, which will have flushed the pipeline, so the value is
       zero. Currently this is optional behavior, since it breaks GDB.
       zero. Currently this is optional behavior, since it breaks GDB.
    */
    */
 
 
    if (config.sim.strict_npc && cpu_state.npc_not_valid)
    if (config.sim.strict_npc && cpu_state.npc_not_valid)
      {
      {
        ret = 0;
        ret = 0;
      }
      }
    else
    else
      {
      {
        ret = cpu_state.pc;
        ret = cpu_state.pc;
      }
      }
    break;
    break;
 
 
  case SPR_TTCR:
  case SPR_TTCR:
    ret = spr_read_ttcr();
    ret = spr_read_ttcr();
    break;
    break;
  case SPR_FPCSR:
  case SPR_FPCSR:
    // If hard floating point is disabled - return 0
    // If hard floating point is disabled - return 0
    if (!config.cpu.hardfloat)
    if (!config.cpu.hardfloat)
      ret = 0;
      ret = 0;
    break;
    break;
  default:
  default:
    /* Links to GPRS */
    /* Links to GPRS */
    if(regno >= 0x0400 && regno < 0x0420)
    if(regno >= 0x0400 && regno < 0x0420)
      ret = cpu_state.reg[regno - 0x0400];
      ret = cpu_state.reg[regno - 0x0400];
  }
  }
 
 
  return ret;
  return ret;
}
}
 
 
/* Show status of important SPRs. */
/* Show status of important SPRs. */
void sprs_status(void)
void sprs_status(void)
{
{
  PRINTF("VR   : 0x%"PRIxREG"  UPR  : 0x%"PRIxREG"\n", cpu_state.sprs[SPR_VR],
  PRINTF("VR   : 0x%"PRIxREG"  UPR  : 0x%"PRIxREG"\n", cpu_state.sprs[SPR_VR],
         cpu_state.sprs[SPR_UPR]);
         cpu_state.sprs[SPR_UPR]);
  PRINTF("SR   : 0x%"PRIxREG"\n", cpu_state.sprs[SPR_SR]);
  PRINTF("SR   : 0x%"PRIxREG"\n", cpu_state.sprs[SPR_SR]);
  PRINTF("MACLO: 0x%"PRIxREG"  MACHI: 0x%"PRIxREG"\n",
  PRINTF("MACLO: 0x%"PRIxREG"  MACHI: 0x%"PRIxREG"\n",
         cpu_state.sprs[SPR_MACLO], cpu_state.sprs[SPR_MACHI]);
         cpu_state.sprs[SPR_MACLO], cpu_state.sprs[SPR_MACHI]);
  PRINTF("EPCR0: 0x%"PRIxADDR"  EPCR1: 0x%"PRIxADDR"\n",
  PRINTF("EPCR0: 0x%"PRIxADDR"  EPCR1: 0x%"PRIxADDR"\n",
         cpu_state.sprs[SPR_EPCR_BASE], cpu_state.sprs[SPR_EPCR_BASE+1]);
         cpu_state.sprs[SPR_EPCR_BASE], cpu_state.sprs[SPR_EPCR_BASE+1]);
  PRINTF("EEAR0: 0x%"PRIxADDR"  EEAR1: 0x%"PRIxADDR"\n",
  PRINTF("EEAR0: 0x%"PRIxADDR"  EEAR1: 0x%"PRIxADDR"\n",
         cpu_state.sprs[SPR_EEAR_BASE], cpu_state.sprs[SPR_EEAR_BASE+1]);
         cpu_state.sprs[SPR_EEAR_BASE], cpu_state.sprs[SPR_EEAR_BASE+1]);
  PRINTF("ESR0 : 0x%"PRIxREG"  ESR1 : 0x%"PRIxREG"\n",
  PRINTF("ESR0 : 0x%"PRIxREG"  ESR1 : 0x%"PRIxREG"\n",
         cpu_state.sprs[SPR_ESR_BASE], cpu_state.sprs[SPR_ESR_BASE+1]);
         cpu_state.sprs[SPR_ESR_BASE], cpu_state.sprs[SPR_ESR_BASE+1]);
  PRINTF("TTMR : 0x%"PRIxREG"  TTCR : 0x%"PRIxREG"\n",
  PRINTF("TTMR : 0x%"PRIxREG"  TTCR : 0x%"PRIxREG"\n",
         cpu_state.sprs[SPR_TTMR], cpu_state.sprs[SPR_TTCR]);
         cpu_state.sprs[SPR_TTMR], cpu_state.sprs[SPR_TTCR]);
  PRINTF("PICMR: 0x%"PRIxREG"  PICSR: 0x%"PRIxREG"\n",
  PRINTF("PICMR: 0x%"PRIxREG"  PICSR: 0x%"PRIxREG"\n",
         cpu_state.sprs[SPR_PICMR], cpu_state.sprs[SPR_PICSR]);
         cpu_state.sprs[SPR_PICMR], cpu_state.sprs[SPR_PICSR]);
  PRINTF("PPC:   0x%"PRIxADDR"  NPC   : 0x%"PRIxADDR"\n",
  PRINTF("PPC:   0x%"PRIxADDR"  NPC   : 0x%"PRIxADDR"\n",
         cpu_state.sprs[SPR_PPC], cpu_state.sprs[SPR_NPC]);
         cpu_state.sprs[SPR_PPC], cpu_state.sprs[SPR_NPC]);
}
}
 
 

powered by: WebSVN 2.1.0

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