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

Subversion Repositories openrisc

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

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

Rev 224 Rev 556
/* dmmu.c -- Data MMU simulation
/* dmmu.c -- Data 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. */
 
 
/* DMMU model, perfectly functional. */
/* DMMU model, perfectly functional. */
 
 
 
 
/* 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>
 
 
/* Package includes */
/* Package includes */
#include "dmmu.h"
#include "dmmu.h"
#include "sim-config.h"
#include "sim-config.h"
#include "arch.h"
#include "arch.h"
#include "execute.h"
#include "execute.h"
#include "spr-defs.h"
#include "spr-defs.h"
#include "stats.h"
#include "stats.h"
#include "except.h"
#include "except.h"
#include "sprs.h"
#include "sprs.h"
#include "misc.h"
#include "misc.h"
#include "sim-cmd.h"
#include "sim-cmd.h"
 
#include "pcu.h"
 
 
struct dmmu *dmmu_state;
struct dmmu *dmmu_state;
 
 
/* Data MMU */
/* Data MMU */
 
 
static uorreg_t *
static uorreg_t *
dmmu_find_tlbmr (oraddr_t virtaddr, uorreg_t ** dtlbmr_lru, struct dmmu *dmmu)
dmmu_find_tlbmr (oraddr_t virtaddr, uorreg_t ** dtlbmr_lru, struct dmmu *dmmu)
{
{
  int set;
  int set;
  int i;
  int i;
  oraddr_t vpn;
  oraddr_t vpn;
  uorreg_t *dtlbmr;
  uorreg_t *dtlbmr;
 
 
  /* Which set to check out? */
  /* Which set to check out? */
  set = DADDR_PAGE (virtaddr) >> dmmu->pagesize_log2;
  set = DADDR_PAGE (virtaddr) >> dmmu->pagesize_log2;
  set &= dmmu->set_mask;
  set &= dmmu->set_mask;
  vpn = virtaddr & dmmu->vpn_mask;
  vpn = virtaddr & dmmu->vpn_mask;
 
 
  dtlbmr = &cpu_state.sprs[SPR_DTLBMR_BASE (0) + set];
  dtlbmr = &cpu_state.sprs[SPR_DTLBMR_BASE (0) + set];
  *dtlbmr_lru = dtlbmr;
  *dtlbmr_lru = dtlbmr;
 
 
  /* FIXME: Should this be reversed? */
  /* FIXME: Should this be reversed? */
  for (i = dmmu->nways; i; i--, dtlbmr += (128 * 2))
  for (i = dmmu->nways; i; i--, dtlbmr += (128 * 2))
    {
    {
      if (((*dtlbmr & dmmu->vpn_mask) == vpn) && (*dtlbmr & SPR_DTLBMR_V))
      if (((*dtlbmr & dmmu->vpn_mask) == vpn) && (*dtlbmr & SPR_DTLBMR_V))
        return dtlbmr;
        return dtlbmr;
    }
    }
 
 
  return NULL;
  return NULL;
}
}
 
 
oraddr_t
oraddr_t
dmmu_translate (oraddr_t virtaddr, int write_access)
dmmu_translate (oraddr_t virtaddr, int write_access)
{
{
  int i;
  int i;
  uorreg_t *dtlbmr;
  uorreg_t *dtlbmr;
  uorreg_t *dtlbtr;
  uorreg_t *dtlbtr;
  uorreg_t *dtlbmr_lru;
  uorreg_t *dtlbmr_lru;
  struct dmmu *dmmu = dmmu_state;
  struct dmmu *dmmu = dmmu_state;
 
 
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_DME) ||
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_DME) ||
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP))
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP))
    {
    {
      data_ci = (virtaddr >= 0x80000000);
      data_ci = (virtaddr >= 0x80000000);
      return virtaddr;
      return virtaddr;
    }
    }
 
 
  dtlbmr = dmmu_find_tlbmr (virtaddr, &dtlbmr_lru, dmmu);
  dtlbmr = dmmu_find_tlbmr (virtaddr, &dtlbmr_lru, dmmu);
 
 
  /* Did we find our tlb entry? */
  /* Did we find our tlb entry? */
  if (dtlbmr)
  if (dtlbmr)
    {                           /* Yes, we did. */
    {                           /* Yes, we did. */
      dmmu_stats.loads_tlbhit++;
      dmmu_stats.loads_tlbhit++;
 
 
      dtlbtr = dtlbmr + 128;
      dtlbtr = dtlbmr + 128;
 
 
      /* Set LRUs */
      /* Set LRUs */
      for (i = 0; i < dmmu->nways; i++, dtlbmr_lru += (128 * 2))
      for (i = 0; i < dmmu->nways; i++, dtlbmr_lru += (128 * 2))
        {
        {
          if (*dtlbmr_lru & SPR_DTLBMR_LRU)
          if (*dtlbmr_lru & SPR_DTLBMR_LRU)
            *dtlbmr_lru = (*dtlbmr_lru & ~SPR_DTLBMR_LRU) |
            *dtlbmr_lru = (*dtlbmr_lru & ~SPR_DTLBMR_LRU) |
              ((*dtlbmr_lru & SPR_DTLBMR_LRU) - 0x40);
              ((*dtlbmr_lru & SPR_DTLBMR_LRU) - 0x40);
        }
        }
 
 
      /* This is not necessary `*dtlbmr &= ~SPR_DTLBMR_LRU;' since SPR_DTLBMR_LRU
      /* This is not necessary `*dtlbmr &= ~SPR_DTLBMR_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 */
      *dtlbmr |= dmmu->lru_reload;
      *dtlbmr |= dmmu->lru_reload;
 
 
      /* Check if page is cache inhibited */
      /* Check if page is cache inhibited */
      data_ci = *dtlbtr & SPR_DTLBTR_CI;
      data_ci = *dtlbtr & SPR_DTLBTR_CI;
 
 
      runtime.sim.mem_cycles += dmmu->hitdelay;
      runtime.sim.mem_cycles += dmmu->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 ((write_access && !(*dtlbtr & SPR_DTLBTR_SWE))
          if ((write_access && !(*dtlbtr & SPR_DTLBTR_SWE))
              || (!write_access && !(*dtlbtr & SPR_DTLBTR_SRE)))
              || (!write_access && !(*dtlbtr & SPR_DTLBTR_SRE)))
            except_handle (EXCEPT_DPF, virtaddr);
            except_handle (EXCEPT_DPF, virtaddr);
        }
        }
      else
      else
        {
        {
          if ((write_access && !(*dtlbtr & SPR_DTLBTR_UWE))
          if ((write_access && !(*dtlbtr & SPR_DTLBTR_UWE))
              || (!write_access && !(*dtlbtr & SPR_DTLBTR_URE)))
              || (!write_access && !(*dtlbtr & SPR_DTLBTR_URE)))
            except_handle (EXCEPT_DPF, virtaddr);
            except_handle (EXCEPT_DPF, virtaddr);
        }
        }
 
 
      return (*dtlbtr & SPR_DTLBTR_PPN) | (virtaddr &
      return (*dtlbtr & SPR_DTLBTR_PPN) | (virtaddr &
                                           (dmmu->page_offset_mask));
                                           (dmmu->page_offset_mask));
    }
    }
 
 
  /* No, we didn't. */
  /* No, we didn't. */
  dmmu_stats.loads_tlbmiss++;
  dmmu_stats.loads_tlbmiss++;
#if 0
 
  for (i = 0; i < dmmu->nways; i++)
 
    if (((cpu_state.sprs[SPR_DTLBMR_BASE (i) + set] & SPR_DTLBMR_LRU) >> 6) <
 
        minlru)
 
      minway = i;
 
 
 
  cpu_state.sprs[SPR_DTLBMR_BASE (minway) + set] &= ~SPR_DTLBMR_VPN;
 
  cpu_state.sprs[SPR_DTLBMR_BASE (minway) + set] |= vpn << 12;
 
  for (i = 0; i < dmmu->nways; i++)
 
    {
 
      uorreg_t lru = cpu_state.sprs[SPR_DTLBMR_BASE (i) + set];
 
      if (lru & SPR_DTLBMR_LRU)
 
        {
 
          lru = (lru & ~SPR_DTLBMR_LRU) | ((lru & SPR_DTLBMR_LRU) - 0x40);
 
          cpu_state.sprs[SPR_DTLBMR_BASE (i) + set] = lru;
 
        }
 
    }
 
  cpu_state.sprs[SPR_DTLBMR_BASE (way) + set] &= ~SPR_DTLBMR_LRU;
 
  cpu_state.sprs[SPR_DTLBMR_BASE (way) + set] |= (dmmu->nsets - 1) << 6;
 
 
 
  /* 1 to 1 mapping */
 
  cpu_state.sprs[SPR_DTLBTR_BASE (minway) + set] &= ~SPR_DTLBTR_PPN;
 
  cpu_state.sprs[SPR_DTLBTR_BASE (minway) + set] |= vpn << 12;
 
 
 
  cpu_state.sprs[SPR_DTLBMR_BASE (minway) + set] |= SPR_DTLBMR_V;
 
#endif
 
  runtime.sim.mem_cycles += dmmu->missdelay;
  runtime.sim.mem_cycles += dmmu->missdelay;
  /* if tlb refill implemented in HW */
  /* if tlb refill implemented in HW */
  /* return ((cpu_state.sprs[SPR_DTLBTR_BASE(minway) + set] & SPR_DTLBTR_PPN) >> 12) * dmmu->pagesize + (virtaddr % dmmu->pagesize); */
  /* return ((cpu_state.sprs[SPR_DTLBTR_BASE(minway) + set] & SPR_DTLBTR_PPN) >> 12) * dmmu->pagesize + (virtaddr % dmmu->pagesize); */
 
 
  except_handle (EXCEPT_DTLBMISS, virtaddr);
  except_handle (EXCEPT_DTLBMISS, virtaddr);
 
 
 
  if (config.pcu.enabled)
 
    pcu_count_event(SPR_PCMR_DTLBM);
 
 
  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
 *
 *
 *       write_access - 0 ignore testing for write access
 *       write_access - 0 ignore testing for write access
 *                      1 test for write access, if fails
 *                      1 test for write access, if fails
 *                        do not return translation
 *                        do not return translation
 *
 *
 *       through_dc   - 1 go through data cache
 *       through_dc   - 1 go through data cache
 *                      0 ignore data cache
 *                      0 ignore data cache
 *
 *
 * RTRN: 0            - no DMMU, DMMU disabled or ITLB miss
 * RTRN: 0            - no DMMU, DMMU disabled or ITLB miss
 *       else         - appropriate PA (note it DMMU is not present
 *       else         - appropriate PA (note it DMMU is not present
 *                      PA === EA)
 *                      PA === EA)
 */
 */
oraddr_t
oraddr_t
peek_into_dtlb (oraddr_t virtaddr, int write_access, int through_dc)
peek_into_dtlb (oraddr_t virtaddr, int write_access, int through_dc)
{
{
  uorreg_t *dtlbmr;
  uorreg_t *dtlbmr;
  uorreg_t *dtlbtr;
  uorreg_t *dtlbtr;
  uorreg_t *dtlbmr_lru;
  uorreg_t *dtlbmr_lru;
  struct dmmu *dmmu = dmmu_state;
  struct dmmu *dmmu = dmmu_state;
 
 
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_DME) ||
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_DME) ||
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP))
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP))
    {
    {
      if (through_dc)
      if (through_dc)
        data_ci = (virtaddr >= 0x80000000);
        data_ci = (virtaddr >= 0x80000000);
      return virtaddr;
      return virtaddr;
    }
    }
 
 
  dtlbmr = dmmu_find_tlbmr (virtaddr, &dtlbmr_lru, dmmu);
  dtlbmr = dmmu_find_tlbmr (virtaddr, &dtlbmr_lru, dmmu);
 
 
  /* Did we find our tlb entry? */
  /* Did we find our tlb entry? */
  if (dtlbmr)
  if (dtlbmr)
    {                           /* Yes, we did. */
    {                           /* Yes, we did. */
      dmmu_stats.loads_tlbhit++;
      dmmu_stats.loads_tlbhit++;
 
 
      dtlbtr = dtlbmr + 128;
      dtlbtr = dtlbmr + 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 ((write_access && !(*dtlbtr & SPR_DTLBTR_SWE)) ||
          if ((write_access && !(*dtlbtr & SPR_DTLBTR_SWE)) ||
              (!write_access && !(*dtlbtr & SPR_DTLBTR_SRE)))
              (!write_access && !(*dtlbtr & SPR_DTLBTR_SRE)))
 
 
            /* otherwise exception DPF would be raised */
            /* otherwise exception DPF would be raised */
            return (0);
            return (0);
        }
        }
      else
      else
        {
        {
          if ((write_access && !(*dtlbtr & SPR_DTLBTR_UWE)) ||
          if ((write_access && !(*dtlbtr & SPR_DTLBTR_UWE)) ||
              (!write_access && !(*dtlbtr & SPR_DTLBTR_URE)))
              (!write_access && !(*dtlbtr & SPR_DTLBTR_URE)))
 
 
            /* otherwise exception DPF would be raised */
            /* otherwise exception DPF would be raised */
            return (0);
            return (0);
        }
        }
 
 
      if (through_dc)
      if (through_dc)
        {
        {
          /* Check if page is cache inhibited */
          /* Check if page is cache inhibited */
          data_ci = *dtlbtr & SPR_DTLBTR_CI;
          data_ci = *dtlbtr & SPR_DTLBTR_CI;
        }
        }
 
 
      return (*dtlbtr & SPR_DTLBTR_PPN) | (virtaddr &
      return (*dtlbtr & SPR_DTLBTR_PPN) | (virtaddr &
                                           (dmmu->page_offset_mask));
                                           (dmmu->page_offset_mask));
    }
    }
 
 
  return (0);
  return (0);
}
}
 
 
/* FIXME: Is this comment valid? */
/* FIXME: Is this comment valid? */
/* First check if virtual address is covered by DTLB and if it is:
/* First check if virtual address is covered by DTLB and if it is:
    - increment DTLB read hit stats,
    - increment DTLB read hit stats,
    - set 'lru' at this way to dmmu->ustates - 1 and
    - set 'lru' at this way to dmmu->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 DMMU page fault exception
    - check page access attributes and invoke DMMU page fault exception
      handler if necessary
      handler if necessary
   and if not:
   and if not:
    - increment DTLB read miss stats
    - increment DTLB read miss stats
    - find lru way and entry and invoke DTLB miss exception handler
    - find lru way and entry and invoke DTLB miss exception handler
    - set 'lru' with dmmu->ustates - 1 and decrement 'lru' of other
    - set 'lru' with dmmu->ustates - 1 and decrement 'lru' of other
      ways unless they have reached 0
      ways unless they have reached 0
*/
*/
 
 
static void
static void
dtlb_status (void *dat)
dtlb_status (void *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = dat;
  int set;
  int set;
  int way;
  int way;
  int end_set = dmmu->nsets;
  int end_set = dmmu->nsets;
 
 
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP))
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP))
    {
    {
      PRINTF ("DMMU not implemented. Set UPR[DMP].\n");
      PRINTF ("DMMU not implemented. Set UPR[DMP].\n");
      return;
      return;
    }
    }
 
 
  if (0 < end_set)
  if (0 < end_set)
    PRINTF ("\nDMMU: ");
    PRINTF ("\nDMMU: ");
  /* 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 < dmmu->nways; way++)
      for (way = 0; way < dmmu->nways; way++)
        {
        {
          PRINTF ("%s\n", dump_spr (SPR_DTLBMR_BASE (way) + set,
          PRINTF ("%s\n", dump_spr (SPR_DTLBMR_BASE (way) + set,
                                    cpu_state.sprs[SPR_DTLBMR_BASE (way) +
                                    cpu_state.sprs[SPR_DTLBMR_BASE (way) +
                                                   set]));
                                                   set]));
          PRINTF ("%s\n",
          PRINTF ("%s\n",
                  dump_spr (SPR_DTLBTR_BASE (way) + set,
                  dump_spr (SPR_DTLBTR_BASE (way) + set,
                            cpu_state.sprs[SPR_DTLBTR_BASE (way) + set]));
                            cpu_state.sprs[SPR_DTLBTR_BASE (way) + set]));
        }
        }
    }
    }
  if (0 < end_set)
  if (0 < end_set)
    PRINTF ("\n");
    PRINTF ("\n");
}
}
 
 
/*---------------------------------------------------[ DMMU configuration ]---*/
/*---------------------------------------------------[ DMMU configuration ]---*/
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Enable or disable the DMMU
/*!Enable or disable the DMMU
 
 
   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
dmmu_enabled (union param_val val, void *dat)
dmmu_enabled (union param_val val, void *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = dat;
 
 
  if (val.int_val)
  if (val.int_val)
    {
    {
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_DMP;
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_DMP;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DMP;
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DMP;
    }
    }
 
 
  dmmu->enabled = val.int_val;
  dmmu->enabled = val.int_val;
 
 
}       /* dmmu_enabled() */
}       /* dmmu_enabled() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!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 DMMU configuration flags.
   warning. Set the corresponding DMMU 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
dmmu_nsets (union param_val  val,
dmmu_nsets (union param_val  val,
            void            *dat)
            void            *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = 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);
 
 
      dmmu->nsets = val.int_val;
      dmmu->nsets = val.int_val;
 
 
      cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTS;
      cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTS;
      cpu_state.sprs[SPR_DMMUCFGR] |= set_bits << SPR_DMMUCFGR_NTS_OFF;
      cpu_state.sprs[SPR_DMMUCFGR] |= set_bits << SPR_DMMUCFGR_NTS_OFF;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning DMMU nsets not a power of 2 <= 128: ignored\n");
      fprintf (stderr, "Warning DMMU nsets not a power of 2 <= 128: ignored\n");
    }
    }
}       /* dmmu_nsets() */
}       /* dmmu_nsets() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the number of DMMU ways
/*!Set the number of DMMU ways
 
 
   Value must be in the range 1-4. Ignore other values with a warning. Set the
   Value must be in the range 1-4. Ignore other values with a warning. Set the
   corresponding DMMU configuration flags.
   corresponding DMMU 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
dmmu_nways (union param_val  val,
dmmu_nways (union param_val  val,
            void            *dat)
            void            *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = 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;
 
 
      dmmu->nways = val.int_val;
      dmmu->nways = val.int_val;
 
 
      cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTW;
      cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTW;
      cpu_state.sprs[SPR_DMMUCFGR] |= way_bits << SPR_DMMUCFGR_NTW_OFF;
      cpu_state.sprs[SPR_DMMUCFGR] |= way_bits << SPR_DMMUCFGR_NTW_OFF;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning DMMU nways not in range 1-4: ignored\n");
      fprintf (stderr, "Warning DMMU nways not in range 1-4: ignored\n");
    }
    }
}       /* dmmu_nways() */
}       /* dmmu_nways() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the DMMU page size
/*!Set the DMMU 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
dmmu_pagesize (union param_val  val,
dmmu_pagesize (union param_val  val,
               void            *dat)
               void            *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = dat;
 
 
  if (is_power2 (val.int_val))
  if (is_power2 (val.int_val))
    {
    {
      dmmu->pagesize = val.int_val;
      dmmu->pagesize = val.int_val;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning DMMU page size must be power of 2: ignored\n");
      fprintf (stderr, "Warning DMMU page size must be power of 2: ignored\n");
    }
    }
}       /* dmmu_pagesize() */
}       /* dmmu_pagesize() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the DMMU entry size
/*!Set the DMMU 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
dmmu_entrysize (union param_val  val,
dmmu_entrysize (union param_val  val,
                void            *dat)
                void            *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = dat;
 
 
  if (is_power2 (val.int_val))
  if (is_power2 (val.int_val))
    {
    {
      dmmu->entrysize = val.int_val;
      dmmu->entrysize = val.int_val;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning DMMU entry size must be power of 2: ignored\n");
      fprintf (stderr, "Warning DMMU entry size must be power of 2: ignored\n");
    }
    }
}       /* dmmu_entrysize() */
}       /* dmmu_entrysize() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the number of DMMU usage states
/*!Set the number of DMMU 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
dmmu_ustates (union param_val  val,
dmmu_ustates (union param_val  val,
              void            *dat)
              void            *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = dat;
 
 
  if ((val.int_val >= 2) && (val.int_val <= 4))
  if ((val.int_val >= 2) && (val.int_val <= 4))
    {
    {
      dmmu->ustates = val.int_val;
      dmmu->ustates = val.int_val;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning number of DMMU usage states must be 2, 3 or 4:"
      fprintf (stderr, "Warning number of DMMU usage states must be 2, 3 or 4:"
               "ignored\n");
               "ignored\n");
    }
    }
}       /* dmmu_ustates() */
}       /* dmmu_ustates() */
 
 
 
 
static void
static void
dmmu_missdelay (union param_val val, void *dat)
dmmu_missdelay (union param_val val, void *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = dat;
 
 
  dmmu->missdelay = val.int_val;
  dmmu->missdelay = val.int_val;
}
}
 
 
static void
static void
dmmu_hitdelay (union param_val val, void *dat)
dmmu_hitdelay (union param_val val, void *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = dat;
 
 
  dmmu->hitdelay = val.int_val;
  dmmu->hitdelay = val.int_val;
}
}
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Initialize a new DMMU configuration
/*!Initialize a new DMMU configuration
 
 
   ALL parameters are set explicitly to default values. Corresponding SPR
   ALL parameters are set explicitly to default values. Corresponding SPR
   flags are set as appropriate.
   flags are set as appropriate.
 
 
   @return  The new memory configuration data structure                      */
   @return  The new memory configuration data structure                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void *
static void *
dmmu_start_sec ()
dmmu_start_sec ()
{
{
  struct dmmu *dmmu;
  struct dmmu *dmmu;
  int          set_bits;
  int          set_bits;
  int          way_bits;
  int          way_bits;
 
 
  if (NULL == (dmmu = malloc (sizeof (struct dmmu))))
  if (NULL == (dmmu = malloc (sizeof (struct dmmu))))
    {
    {
      fprintf (stderr, "OOM\n");
      fprintf (stderr, "OOM\n");
      exit (1);
      exit (1);
    }
    }
 
 
  dmmu->enabled   = 0;
  dmmu->enabled   = 0;
  dmmu->nsets     = 1;
  dmmu->nsets     = 1;
  dmmu->nways     = 1;
  dmmu->nways     = 1;
  dmmu->pagesize  = 8192;
  dmmu->pagesize  = 8192;
  dmmu->entrysize = 1;          /* Not currently used */
  dmmu->entrysize = 1;          /* Not currently used */
  dmmu->ustates   = 2;
  dmmu->ustates   = 2;
  dmmu->hitdelay  = 1;
  dmmu->hitdelay  = 1;
  dmmu->missdelay = 1;
  dmmu->missdelay = 1;
 
 
  if (dmmu->enabled)
  if (dmmu->enabled)
    {
    {
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_DMP;
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_DMP;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DMP;
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DMP;
    }
    }
 
 
  set_bits = log2_int (dmmu->nsets);
  set_bits = log2_int (dmmu->nsets);
  cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTS;
  cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTS;
  cpu_state.sprs[SPR_DMMUCFGR] |= set_bits << SPR_DMMUCFGR_NTS_OFF;
  cpu_state.sprs[SPR_DMMUCFGR] |= set_bits << SPR_DMMUCFGR_NTS_OFF;
 
 
  way_bits = dmmu->nways - 1;
  way_bits = dmmu->nways - 1;
  cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTW;
  cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTW;
  cpu_state.sprs[SPR_DMMUCFGR] |= way_bits << SPR_DMMUCFGR_NTW_OFF;
  cpu_state.sprs[SPR_DMMUCFGR] |= way_bits << SPR_DMMUCFGR_NTW_OFF;
 
 
  dmmu_state = dmmu;
  dmmu_state = dmmu;
  return dmmu;
  return dmmu;
 
 
}       /* dmmu_start_sec() */
}       /* dmmu_start_sec() */
 
 
 
 
static void
static void
dmmu_end_sec (void *dat)
dmmu_end_sec (void *dat)
{
{
  struct dmmu *dmmu = dat;
  struct dmmu *dmmu = dat;
 
 
  /* Precalculate some values for use during address translation */
  /* Precalculate some values for use during address translation */
  dmmu->pagesize_log2 = log2_int (dmmu->pagesize);
  dmmu->pagesize_log2 = log2_int (dmmu->pagesize);
  dmmu->page_offset_mask = dmmu->pagesize - 1;
  dmmu->page_offset_mask = dmmu->pagesize - 1;
  dmmu->page_mask = ~dmmu->page_offset_mask;
  dmmu->page_mask = ~dmmu->page_offset_mask;
  dmmu->vpn_mask = ~((dmmu->pagesize * dmmu->nsets) - 1);
  dmmu->vpn_mask = ~((dmmu->pagesize * dmmu->nsets) - 1);
  dmmu->set_mask = dmmu->nsets - 1;
  dmmu->set_mask = dmmu->nsets - 1;
  dmmu->lru_reload = (dmmu->set_mask << 6) & SPR_DTLBMR_LRU;
  dmmu->lru_reload = (dmmu->set_mask << 6) & SPR_DTLBMR_LRU;
 
 
  if (dmmu->enabled)
  if (dmmu->enabled)
    {
    {
      PRINTF ("Data MMU %dKB: %d ways, %d sets, entry size %d bytes\n",
      PRINTF ("Data MMU %dKB: %d ways, %d sets, entry size %d bytes\n",
              dmmu->nsets * dmmu->entrysize * dmmu->nways / 1024, dmmu->nways,
              dmmu->nsets * dmmu->entrysize * dmmu->nways / 1024, dmmu->nways,
              dmmu->nsets, dmmu->entrysize);
              dmmu->nsets, dmmu->entrysize);
      reg_sim_stat (dtlb_status, dmmu);
      reg_sim_stat (dtlb_status, dmmu);
    }
    }
}
}
 
 
void
void
reg_dmmu_sec (void)
reg_dmmu_sec (void)
{
{
  struct config_section *sec = reg_config_sec ("dmmu", dmmu_start_sec,
  struct config_section *sec = reg_config_sec ("dmmu", dmmu_start_sec,
                                               dmmu_end_sec);
                                               dmmu_end_sec);
 
 
  reg_config_param (sec, "enabled",   PARAMT_INT, dmmu_enabled);
  reg_config_param (sec, "enabled",   PARAMT_INT, dmmu_enabled);
  reg_config_param (sec, "nsets",     PARAMT_INT, dmmu_nsets);
  reg_config_param (sec, "nsets",     PARAMT_INT, dmmu_nsets);
  reg_config_param (sec, "nways",     PARAMT_INT, dmmu_nways);
  reg_config_param (sec, "nways",     PARAMT_INT, dmmu_nways);
  reg_config_param (sec, "pagesize",  PARAMT_INT, dmmu_pagesize);
  reg_config_param (sec, "pagesize",  PARAMT_INT, dmmu_pagesize);
  reg_config_param (sec, "entrysize", PARAMT_INT, dmmu_entrysize);
  reg_config_param (sec, "entrysize", PARAMT_INT, dmmu_entrysize);
  reg_config_param (sec, "ustates",   PARAMT_INT, dmmu_ustates);
  reg_config_param (sec, "ustates",   PARAMT_INT, dmmu_ustates);
  reg_config_param (sec, "hitdelay",  PARAMT_INT, dmmu_hitdelay);
  reg_config_param (sec, "hitdelay",  PARAMT_INT, dmmu_hitdelay);
  reg_config_param (sec, "missdelay", PARAMT_INT, dmmu_missdelay);
  reg_config_param (sec, "missdelay", PARAMT_INT, dmmu_missdelay);
}
}
 
 

powered by: WebSVN 2.1.0

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