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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [mmu/] [immu.c] - Diff between revs 224 and 556

Only display areas with differences | Details | Blame | View Log

Rev 224 Rev 556
/* immu.c -- Instruction MMU simulation
/* immu.c -- Instruction MMU simulation
 
 
   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"
 
 
/* System includes */
/* System includes */
#include <stdlib.h>
#include <stdlib.h>
 
 
/* Package includes */
/* Package includes */
#include "immu.h"
#include "immu.h"
#include "sim-config.h"
#include "sim-config.h"
#include "execute.h"
#include "execute.h"
#include "stats.h"
#include "stats.h"
#include "except.h"
#include "except.h"
#include "spr-dump.h"
#include "spr-dump.h"
#include "misc.h"
#include "misc.h"
#include "sim-cmd.h"
#include "sim-cmd.h"
 
#include "pcu.h"
 
 
 
 
struct immu *immu_state;
struct immu *immu_state;
 
 
/* Insn MMU */
/* Insn MMU */
 
 
static uorreg_t *
static uorreg_t *
immu_find_tlbmr (oraddr_t virtaddr, uorreg_t ** itlbmr_lru, struct immu *immu)
immu_find_tlbmr (oraddr_t virtaddr, uorreg_t ** itlbmr_lru, struct immu *immu)
{
{
  int set;
  int set;
  int i;
  int i;
  oraddr_t vpn;
  oraddr_t vpn;
  uorreg_t *itlbmr;
  uorreg_t *itlbmr;
 
 
  /* Which set to check out? */
  /* Which set to check out? */
  set = IADDR_PAGE (virtaddr) >> immu->pagesize_log2;
  set = IADDR_PAGE (virtaddr) >> immu->pagesize_log2;
  set &= immu->set_mask;
  set &= immu->set_mask;
  vpn = virtaddr & immu->vpn_mask;
  vpn = virtaddr & immu->vpn_mask;
 
 
  itlbmr = &cpu_state.sprs[SPR_ITLBMR_BASE (0) + set];
  itlbmr = &cpu_state.sprs[SPR_ITLBMR_BASE (0) + set];
  *itlbmr_lru = itlbmr;
  *itlbmr_lru = itlbmr;
 
 
  /* Scan all ways and try to find a matching way. */
  /* Scan all ways and try to find a matching way. */
  /* FIXME: Should this be reversed? */
  /* FIXME: Should this be reversed? */
  for (i = immu->nways; i; i--, itlbmr += (128 * 2))
  for (i = immu->nways; i; i--, itlbmr += (128 * 2))
    {
    {
      if (((*itlbmr & immu->vpn_mask) == vpn) && (*itlbmr & SPR_ITLBMR_V))
      if (((*itlbmr & immu->vpn_mask) == vpn) && (*itlbmr & SPR_ITLBMR_V))
        return itlbmr;
        return itlbmr;
    }
    }
 
 
  return NULL;
  return NULL;
}
}
 
 
oraddr_t
oraddr_t
immu_translate (oraddr_t virtaddr)
immu_translate (oraddr_t virtaddr)
{
{
  int i;
  int i;
  uorreg_t *itlbmr;
  uorreg_t *itlbmr;
  uorreg_t *itlbtr;
  uorreg_t *itlbtr;
  uorreg_t *itlbmr_lru;
  uorreg_t *itlbmr_lru;
  struct immu *immu = immu_state;
  struct immu *immu = immu_state;
 
 
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
    {
    {
      insn_ci = (virtaddr >= 0x80000000);
      insn_ci = (virtaddr >= 0x80000000);
      return virtaddr;
      return virtaddr;
    }
    }
 
 
  itlbmr = immu_find_tlbmr (virtaddr, &itlbmr_lru, immu);
  itlbmr = immu_find_tlbmr (virtaddr, &itlbmr_lru, immu);
 
 
  /* Did we find our tlb entry? */
  /* Did we find our tlb entry? */
  if (itlbmr)
  if (itlbmr)
    {                           /* Yes, we did. */
    {                           /* Yes, we did. */
      immu_stats.fetch_tlbhit++;
      immu_stats.fetch_tlbhit++;
      itlbtr = itlbmr + 128;
      itlbtr = itlbmr + 128;
 
 
      /* Set LRUs */
      /* Set LRUs */
      for (i = 0; i < immu->nways; i++, itlbmr_lru += (128 * 2))
      for (i = 0; i < immu->nways; i++, itlbmr_lru += (128 * 2))
        {
        {
          if (*itlbmr_lru & SPR_ITLBMR_LRU)
          if (*itlbmr_lru & SPR_ITLBMR_LRU)
            *itlbmr_lru = (*itlbmr_lru & ~SPR_ITLBMR_LRU) |
            *itlbmr_lru = (*itlbmr_lru & ~SPR_ITLBMR_LRU) |
              ((*itlbmr_lru & SPR_ITLBMR_LRU) - 0x40);
              ((*itlbmr_lru & SPR_ITLBMR_LRU) - 0x40);
        }
        }
 
 
      /* This is not necessary `*itlbmr &= ~SPR_ITLBMR_LRU;' since SPR_DTLBMR_LRU
      /* This is not necessary `*itlbmr &= ~SPR_ITLBMR_LRU;' since SPR_DTLBMR_LRU
       * is always decremented and the number of sets is always a power of two and
       * is always decremented and the number of sets is always a power of two and
       * as such lru_reload has all bits set that get touched during decrementing
       * as such lru_reload has all bits set that get touched during decrementing
       * SPR_DTLBMR_LRU */
       * SPR_DTLBMR_LRU */
      *itlbmr |= immu->lru_reload;
      *itlbmr |= immu->lru_reload;
 
 
      /* Check if page is cache inhibited */
      /* Check if page is cache inhibited */
      insn_ci = *itlbtr & SPR_ITLBTR_CI;
      insn_ci = *itlbtr & SPR_ITLBTR_CI;
 
 
      runtime.sim.mem_cycles += immu->hitdelay;
      runtime.sim.mem_cycles += immu->hitdelay;
 
 
      /* Test for page fault */
      /* Test for page fault */
      if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
      if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
        {
        {
          if (!(*itlbtr & SPR_ITLBTR_SXE))
          if (!(*itlbtr & SPR_ITLBTR_SXE))
            except_handle (EXCEPT_IPF, virtaddr);
            except_handle (EXCEPT_IPF, virtaddr);
        }
        }
      else
      else
        {
        {
          if (!(*itlbtr & SPR_ITLBTR_UXE))
          if (!(*itlbtr & SPR_ITLBTR_UXE))
            except_handle (EXCEPT_IPF, virtaddr);
            except_handle (EXCEPT_IPF, virtaddr);
        }
        }
 
 
      return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask);
      return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask);
    }
    }
 
 
  /* No, we didn't. */
  /* No, we didn't. */
  immu_stats.fetch_tlbmiss++;
  immu_stats.fetch_tlbmiss++;
#if 0
 
  for (i = 0; i < immu->nways; i++)
 
    if (((cpu_state.sprs[SPR_ITLBMR_BASE (i) + set] & SPR_ITLBMR_LRU) >> 6) <
 
        minlru)
 
      minway = i;
 
 
 
  cpu_state.sprs[SPR_ITLBMR_BASE (minway) + set] &= ~SPR_ITLBMR_VPN;
 
  cpu_state.sprs[SPR_ITLBMR_BASE (minway) + set] |= vpn << 12;
 
  for (i = 0; i < immu->nways; i++)
 
    {
 
      uorreg_t lru = cpu_state.sprs[SPR_ITLBMR_BASE (i) + set];
 
      if (lru & SPR_ITLBMR_LRU)
 
        {
 
          lru = (lru & ~SPR_ITLBMR_LRU) | ((lru & SPR_ITLBMR_LRU) - 0x40);
 
          cpu_state.sprs[SPR_ITLBMR_BASE (i) + set] = lru;
 
        }
 
    }
 
  cpu_state.sprs[SPR_ITLBMR_BASE (way) + set] &= ~SPR_ITLBMR_LRU;
 
  cpu_state.sprs[SPR_ITLBMR_BASE (way) + set] |= (immu->nsets - 1) << 6;
 
 
 
  /* 1 to 1 mapping */
 
  cpu_state.sprs[SPR_ITLBTR_BASE (minway) + set] &= ~SPR_ITLBTR_PPN;
 
  cpu_state.sprs[SPR_ITLBTR_BASE (minway) + set] |= vpn << 12;
 
 
 
  cpu_state.sprs[SPR_ITLBMR_BASE (minway) + set] |= SPR_ITLBMR_V;
 
#endif
 
 
 
  /* if tlb refill implemented in HW */
  /* if tlb refill implemented in HW */
  /* return ((cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] & SPR_ITLBTR_PPN) >> 12) * immu->pagesize + (virtaddr % immu->pagesize); */
  /* return ((cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] & SPR_ITLBTR_PPN) >> 12) * immu->pagesize + (virtaddr % immu->pagesize); */
  runtime.sim.mem_cycles += immu->missdelay;
  runtime.sim.mem_cycles += immu->missdelay;
 
 
  except_handle (EXCEPT_ITLBMISS, virtaddr);
  except_handle (EXCEPT_ITLBMISS, virtaddr);
 
 
 
  if (config.pcu.enabled)
 
    pcu_count_event(SPR_PCMR_ITLBM);
 
 
  return 0;
  return 0;
}
}
 
 
/* DESC: try to find EA -> PA transaltion without changing
/* DESC: try to find EA -> PA transaltion without changing
 *       any of precessor states. if this is not passible gives up
 *       any of precessor states. if this is not passible gives up
 *       (without triggering exceptions).
 *       (without triggering exceptions).
 *
 *
 * PRMS: virtaddr  - EA for which to find translation
 * PRMS: virtaddr  - EA for which to find translation
 *
 *
 * RTRN: 0         - no IMMU, IMMU disabled or ITLB miss
 * RTRN: 0         - no IMMU, IMMU disabled or ITLB miss
 *       else      - appropriate PA (note it IMMU is not present
 *       else      - appropriate PA (note it IMMU is not present
 *                   PA === EA)
 *                   PA === EA)
 */
 */
oraddr_t
oraddr_t
peek_into_itlb (oraddr_t virtaddr)
peek_into_itlb (oraddr_t virtaddr)
{
{
  uorreg_t *itlbmr;
  uorreg_t *itlbmr;
  uorreg_t *itlbtr;
  uorreg_t *itlbtr;
  uorreg_t *itlbmr_lru;
  uorreg_t *itlbmr_lru;
  struct immu *immu = immu_state;
  struct immu *immu = immu_state;
 
 
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
    {
    {
      return (virtaddr);
      return (virtaddr);
    }
    }
 
 
  itlbmr = immu_find_tlbmr (virtaddr, &itlbmr_lru, immu);
  itlbmr = immu_find_tlbmr (virtaddr, &itlbmr_lru, immu);
 
 
  /* Did we find our tlb entry? */
  /* Did we find our tlb entry? */
  if (itlbmr)
  if (itlbmr)
    {                           /* Yes, we did. */
    {                           /* Yes, we did. */
      itlbtr = itlbmr + 128;
      itlbtr = itlbmr + 128;
 
 
      /* Test for page fault */
      /* Test for page fault */
      if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
      if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
        {
        {
          if (!(*itlbtr & SPR_ITLBTR_SXE))
          if (!(*itlbtr & SPR_ITLBTR_SXE))
            {
            {
              /* no luck, giving up */
              /* no luck, giving up */
              return (0);
              return (0);
            }
            }
        }
        }
      else
      else
        {
        {
          if (!(*itlbtr & SPR_ITLBTR_UXE))
          if (!(*itlbtr & SPR_ITLBTR_UXE))
            {
            {
              /* no luck, giving up */
              /* no luck, giving up */
              return (0);
              return (0);
            }
            }
        }
        }
 
 
      return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask);
      return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask);
    }
    }
 
 
  return (0);
  return (0);
}
}
 
 
 
 
/* FIXME: Check validity */
/* FIXME: Check validity */
/* First check if virtual address is covered by ITLB and if it is:
/* First check if virtual address is covered by ITLB and if it is:
    - increment ITLB read hit stats,
    - increment ITLB read hit stats,
    - set 'lru' at this way to immu->ustates - 1 and
    - set 'lru' at this way to immu->ustates - 1 and
      decrement 'lru' of other ways unless they have reached 0,
      decrement 'lru' of other ways unless they have reached 0,
    - check page access attributes and invoke IMMU page fault exception
    - check page access attributes and invoke IMMU page fault exception
      handler if necessary
      handler if necessary
   and if not:
   and if not:
    - increment ITLB read miss stats
    - increment ITLB read miss stats
    - find lru way and entry and invoke ITLB miss exception handler
    - find lru way and entry and invoke ITLB miss exception handler
    - set 'lru' with immu->ustates - 1 and decrement 'lru' of other
    - set 'lru' with immu->ustates - 1 and decrement 'lru' of other
      ways unless they have reached 0
      ways unless they have reached 0
*/
*/
 
 
static void
static void
itlb_status (void *dat)
itlb_status (void *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
  int set;
  int set;
  int way;
  int way;
  int end_set = immu->nsets;
  int end_set = immu->nsets;
 
 
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
    {
    {
      PRINTF ("IMMU not implemented. Set UPR[IMP].\n");
      PRINTF ("IMMU not implemented. Set UPR[IMP].\n");
      return;
      return;
    }
    }
 
 
  if (0 < end_set)
  if (0 < end_set)
    PRINTF ("\nIMMU: ");
    PRINTF ("\nIMMU: ");
  /* Scan set(s) and way(s). */
  /* Scan set(s) and way(s). */
  for (set = 0; set < end_set; set++)
  for (set = 0; set < end_set; set++)
    {
    {
      for (way = 0; way < immu->nways; way++)
      for (way = 0; way < immu->nways; way++)
        {
        {
          PRINTF ("%s\n", dump_spr (SPR_ITLBMR_BASE (way) + set,
          PRINTF ("%s\n", dump_spr (SPR_ITLBMR_BASE (way) + set,
                                    cpu_state.sprs[SPR_ITLBMR_BASE (way) +
                                    cpu_state.sprs[SPR_ITLBMR_BASE (way) +
                                                   set]));
                                                   set]));
          PRINTF ("%s\n",
          PRINTF ("%s\n",
                  dump_spr (SPR_ITLBTR_BASE (way) + set,
                  dump_spr (SPR_ITLBTR_BASE (way) + set,
                            cpu_state.sprs[SPR_ITLBTR_BASE (way) + set]));
                            cpu_state.sprs[SPR_ITLBTR_BASE (way) + set]));
        }
        }
    }
    }
  if (0 < end_set)
  if (0 < end_set)
    PRINTF ("\n");
    PRINTF ("\n");
}
}
 
 
/*---------------------------------------------------[ IMMU configuration ]---*/
/*---------------------------------------------------[ IMMU configuration ]---*/
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Enable or disable the IMMU
/*!Enable or disable the IMMU
 
 
   Set the corresponding field in the UPR
   Set the corresponding field in the UPR
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
immu_enabled (union param_val val, void *dat)
immu_enabled (union param_val val, void *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  if (val.int_val)
  if (val.int_val)
    {
    {
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
    }
    }
 
 
  immu->enabled = val.int_val;
  immu->enabled = val.int_val;
}
}
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the number of DMMU sets
/*!Set the number of DMMU sets
 
 
   Value must be a power of 2 <= 256. Ignore any other values with a
   Value must be a power of 2 <= 256. Ignore any other values with a
   warning. Set the corresponding IMMU configuration flags.
   warning. Set the corresponding IMMU configuration flags.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
immu_nsets (union param_val  val,
immu_nsets (union param_val  val,
            void            *dat)
            void            *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  if (is_power2 (val.int_val) && (val.int_val <= 128))
  if (is_power2 (val.int_val) && (val.int_val <= 128))
    {
    {
      int  set_bits = log2_int (val.int_val);
      int  set_bits = log2_int (val.int_val);
 
 
      immu->nsets = val.int_val;
      immu->nsets = val.int_val;
 
 
      cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
      cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
      cpu_state.sprs[SPR_IMMUCFGR] |= set_bits << SPR_IMMUCFGR_NTS_OFF;
      cpu_state.sprs[SPR_IMMUCFGR] |= set_bits << SPR_IMMUCFGR_NTS_OFF;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning IMMU nsets not a power of 2 <= 128: ignored\n");
      fprintf (stderr, "Warning IMMU nsets not a power of 2 <= 128: ignored\n");
    }
    }
}       /* immu_nsets() */
}       /* immu_nsets() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the number of IMMU ways
/*!Set the number of IMMU ways
 
 
   Value must be in the range 1-4. Ignore other values with a warning.  Set
   Value must be in the range 1-4. Ignore other values with a warning.  Set
   the corresponding IMMU configuration flags.
   the corresponding IMMU configuration flags.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
immu_nways (union param_val  val,
immu_nways (union param_val  val,
            void            *dat)
            void            *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  if (val.int_val >= 1 && val.int_val <= 4)
  if (val.int_val >= 1 && val.int_val <= 4)
    {
    {
      int  way_bits = val.int_val - 1;
      int  way_bits = val.int_val - 1;
 
 
      immu->nways = val.int_val;
      immu->nways = val.int_val;
 
 
      cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
      cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
      cpu_state.sprs[SPR_IMMUCFGR] |= way_bits << SPR_IMMUCFGR_NTW_OFF;
      cpu_state.sprs[SPR_IMMUCFGR] |= way_bits << SPR_IMMUCFGR_NTW_OFF;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning IMMU nways not in range 1-4: ignored\n");
      fprintf (stderr, "Warning IMMU nways not in range 1-4: ignored\n");
    }
    }
}       /* immu_nways() */
}       /* immu_nways() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the IMMU page size
/*!Set the IMMU page size
 
 
   Value must be a power of 2. Ignore other values with a warning
   Value must be a power of 2. Ignore other values with a warning
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
immu_pagesize (union param_val  val,
immu_pagesize (union param_val  val,
               void            *dat)
               void            *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  if (is_power2 (val.int_val))
  if (is_power2 (val.int_val))
    {
    {
      immu->pagesize = val.int_val;
      immu->pagesize = val.int_val;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning IMMU page size must be power of 2: ignored\n");
      fprintf (stderr, "Warning IMMU page size must be power of 2: ignored\n");
    }
    }
}       /* immu_pagesize() */
}       /* immu_pagesize() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the IMMU entry size
/*!Set the IMMU entry size
 
 
   Value must be a power of 2. Ignore other values with a warning
   Value must be a power of 2. Ignore other values with a warning
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
immu_entrysize (union param_val  val,
immu_entrysize (union param_val  val,
                void            *dat)
                void            *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  if (is_power2 (val.int_val))
  if (is_power2 (val.int_val))
    {
    {
      immu->entrysize = val.int_val;
      immu->entrysize = val.int_val;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning IMMU entry size must be power of 2: ignored\n");
      fprintf (stderr, "Warning IMMU entry size must be power of 2: ignored\n");
    }
    }
}       /* immu_entrysize() */
}       /* immu_entrysize() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the number of IMMU usage states
/*!Set the number of IMMU usage states
 
 
   Value must be 2, 3 or 4. Ignore other values with a warning
   Value must be 2, 3 or 4. Ignore other values with a warning
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
immu_ustates (union param_val  val,
immu_ustates (union param_val  val,
              void            *dat)
              void            *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  if ((val.int_val >= 2) && (val.int_val <= 4))
  if ((val.int_val >= 2) && (val.int_val <= 4))
    {
    {
      immu->ustates = val.int_val;
      immu->ustates = val.int_val;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning number of IMMU usage states must be 2, 3 or 4:"
      fprintf (stderr, "Warning number of IMMU usage states must be 2, 3 or 4:"
               "ignored\n");
               "ignored\n");
    }
    }
}       /* immu_ustates() */
}       /* immu_ustates() */
 
 
 
 
static void
static void
immu_missdelay (union param_val val, void *dat)
immu_missdelay (union param_val val, void *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  immu->missdelay = val.int_val;
  immu->missdelay = val.int_val;
}
}
 
 
static void
static void
immu_hitdelay (union param_val val, void *dat)
immu_hitdelay (union param_val val, void *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  immu->hitdelay = val.int_val;
  immu->hitdelay = val.int_val;
}
}
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Initialize a new DMMU configuration
/*!Initialize a new DMMU configuration
 
 
   ALL parameters are set explicitly to default values.                      */
   ALL parameters are set explicitly to default values.                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void *
static void *
immu_start_sec ()
immu_start_sec ()
{
{
  struct immu *immu;
  struct immu *immu;
  int          set_bits;
  int          set_bits;
  int          way_bits;
  int          way_bits;
 
 
  if (NULL == (immu = malloc (sizeof (struct immu))))
  if (NULL == (immu = malloc (sizeof (struct immu))))
    {
    {
      fprintf (stderr, "OOM\n");
      fprintf (stderr, "OOM\n");
      exit (1);
      exit (1);
    }
    }
 
 
  immu->enabled   = 0;
  immu->enabled   = 0;
  immu->nsets     = 1;
  immu->nsets     = 1;
  immu->nways     = 1;
  immu->nways     = 1;
  immu->pagesize  = 8192;
  immu->pagesize  = 8192;
  immu->entrysize = 1;          /* Not currently used */
  immu->entrysize = 1;          /* Not currently used */
  immu->ustates   = 2;
  immu->ustates   = 2;
  immu->hitdelay  = 1;
  immu->hitdelay  = 1;
  immu->missdelay = 1;
  immu->missdelay = 1;
 
 
  if (immu->enabled)
  if (immu->enabled)
    {
    {
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
    }
    }
 
 
  set_bits = log2_int (immu->nsets);
  set_bits = log2_int (immu->nsets);
  cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
  cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
  cpu_state.sprs[SPR_IMMUCFGR] |= set_bits << SPR_IMMUCFGR_NTS_OFF;
  cpu_state.sprs[SPR_IMMUCFGR] |= set_bits << SPR_IMMUCFGR_NTS_OFF;
 
 
  way_bits = immu->nways - 1;
  way_bits = immu->nways - 1;
  cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
  cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
  cpu_state.sprs[SPR_IMMUCFGR] |= way_bits << SPR_IMMUCFGR_NTW_OFF;
  cpu_state.sprs[SPR_IMMUCFGR] |= way_bits << SPR_IMMUCFGR_NTW_OFF;
 
 
  immu_state = immu;
  immu_state = immu;
  return immu;
  return immu;
 
 
}       /* immu_start_sec() */
}       /* immu_start_sec() */
 
 
 
 
static void
static void
immu_end_sec (void *dat)
immu_end_sec (void *dat)
{
{
  struct immu *immu = dat;
  struct immu *immu = dat;
 
 
  /* Precalculate some values for use during address translation */
  /* Precalculate some values for use during address translation */
  immu->pagesize_log2 = log2_int (immu->pagesize);
  immu->pagesize_log2 = log2_int (immu->pagesize);
  immu->page_offset_mask = immu->pagesize - 1;
  immu->page_offset_mask = immu->pagesize - 1;
  immu->page_mask = ~immu->page_offset_mask;
  immu->page_mask = ~immu->page_offset_mask;
  immu->vpn_mask = ~((immu->pagesize * immu->nsets) - 1);
  immu->vpn_mask = ~((immu->pagesize * immu->nsets) - 1);
  immu->set_mask = immu->nsets - 1;
  immu->set_mask = immu->nsets - 1;
  immu->lru_reload = (immu->set_mask << 6) & SPR_ITLBMR_LRU;
  immu->lru_reload = (immu->set_mask << 6) & SPR_ITLBMR_LRU;
 
 
  if (immu->enabled)
  if (immu->enabled)
    {
    {
      PRINTF ("Insn MMU %dKB: %d ways, %d sets, entry size %d bytes\n",
      PRINTF ("Insn MMU %dKB: %d ways, %d sets, entry size %d bytes\n",
              immu->nsets * immu->entrysize * immu->nways / 1024, immu->nways,
              immu->nsets * immu->entrysize * immu->nways / 1024, immu->nways,
              immu->nsets, immu->entrysize);
              immu->nsets, immu->entrysize);
      reg_sim_stat (itlb_status, immu);
      reg_sim_stat (itlb_status, immu);
    }
    }
}
}
 
 
void
void
reg_immu_sec (void)
reg_immu_sec (void)
{
{
  struct config_section *sec = reg_config_sec ("immu", immu_start_sec,
  struct config_section *sec = reg_config_sec ("immu", immu_start_sec,
                                               immu_end_sec);
                                               immu_end_sec);
 
 
  reg_config_param (sec, "enabled",   PARAMT_INT, immu_enabled);
  reg_config_param (sec, "enabled",   PARAMT_INT, immu_enabled);
  reg_config_param (sec, "nsets",     PARAMT_INT, immu_nsets);
  reg_config_param (sec, "nsets",     PARAMT_INT, immu_nsets);
  reg_config_param (sec, "nways",     PARAMT_INT, immu_nways);
  reg_config_param (sec, "nways",     PARAMT_INT, immu_nways);
  reg_config_param (sec, "pagesize",  PARAMT_INT, immu_pagesize);
  reg_config_param (sec, "pagesize",  PARAMT_INT, immu_pagesize);
  reg_config_param (sec, "entrysize", PARAMT_INT, immu_entrysize);
  reg_config_param (sec, "entrysize", PARAMT_INT, immu_entrysize);
  reg_config_param (sec, "ustates",   PARAMT_INT, immu_ustates);
  reg_config_param (sec, "ustates",   PARAMT_INT, immu_ustates);
  reg_config_param (sec, "missdelay", PARAMT_INT, immu_missdelay);
  reg_config_param (sec, "missdelay", PARAMT_INT, immu_missdelay);
  reg_config_param (sec, "hitdelay",  PARAMT_INT, immu_hitdelay);
  reg_config_param (sec, "hitdelay",  PARAMT_INT, immu_hitdelay);
}
}
 
 

powered by: WebSVN 2.1.0

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