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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [mmu/] [immu.c] - Diff between revs 1532 and 1538

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

Rev 1532 Rev 1538
Line 15... Line 15...
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 
/* IMMU model (not functional yet, currently just copy of data cache). */
/* IMMU model, perfectly functional. */
 
 
#include "config.h"
#include "config.h"
 
 
#ifdef HAVE_INTTYPES_H
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#include <inttypes.h>
Line 40... Line 40...
 
 
DEFAULT_DEBUG_CHANNEL(immu);
DEFAULT_DEBUG_CHANNEL(immu);
 
 
/* Insn MMU */
/* Insn MMU */
 
 
static inline oraddr_t immu_simulate_tlb(oraddr_t virtaddr)
/* Precalculates some values for use during address translation */
 
void init_immu(void)
 
{
 
  config.immu.pagesize_log2 = log2(config.immu.pagesize);
 
  config.immu.page_offset_mask = config.immu.pagesize - 1;
 
  config.immu.page_mask = ~config.immu.page_offset_mask;
 
  config.immu.vpn_mask = ~((config.immu.pagesize * config.immu.nsets) - 1);
 
  config.immu.set_mask = config.immu.nsets - 1;
 
  config.immu.lru_reload = (config.immu.set_mask << 6) & SPR_ITLBMR_LRU;
 
}
 
 
 
inline uorreg_t *immu_find_tlbmr(oraddr_t virtaddr, uorreg_t **itlbmr_lru)
 
{
 
  int set;
 
  int i;
 
  oraddr_t vpn;
 
  uorreg_t *itlbmr;
 
 
 
  /* Which set to check out? */
 
  set = IADDR_PAGE(virtaddr) >> config.immu.pagesize_log2;
 
  set &= config.immu.set_mask;
 
  vpn = virtaddr & config.immu.vpn_mask;
 
 
 
  itlbmr = &cpu_state.sprs[SPR_ITLBMR_BASE(0) + set];
 
  *itlbmr_lru = itlbmr;
 
 
 
  /* Scan all ways and try to find a matching way. */
 
  /* FIXME: Should this be reversed? */
 
  for(i = config.immu.nways; i; i--, itlbmr += (128 * 2)) {
 
    if(((*itlbmr & config.immu.vpn_mask) == vpn) && (*itlbmr & SPR_ITLBMR_V))
 
      return itlbmr;
 
  }
 
 
 
  return NULL;
 
}
 
 
 
oraddr_t immu_translate(oraddr_t virtaddr)
{
{
  int set, way = -1;
 
  int i;
  int i;
  oraddr_t tagaddr;
  uorreg_t *itlbmr;
  oraddr_t vpn, ppn;
  uorreg_t *itlbtr;
 
  uorreg_t *itlbmr_lru;
 
 
  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;
  }
  }
 
 
  TRACE("IMMU enabled, checking mmu ways\n");
  itlbmr = immu_find_tlbmr(virtaddr, &itlbmr_lru);
 
 
  /* Which set to check out? */
 
  set = (virtaddr / config.immu.pagesize) % config.immu.nsets;
 
  tagaddr = (virtaddr / config.immu.pagesize) / config.immu.nsets;
 
  vpn = virtaddr / (config.immu.pagesize * config.immu.nsets);
 
 
 
  /* Scan all ways and try to find a matching way. */
 
  for (i = 0; i < config.immu.nways; i++)
 
    if (((cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] / (config.immu.pagesize * config.immu.nsets)) == vpn) &&
 
        (cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_V))
 
      way = i;
 
 
 
  /* Did we find our tlb entry? */
  /* Did we find our tlb entry? */
  if (way >= 0) { /* Yes, we did. */
  if(itlbmr) { /* Yes, we did. */
    immu_stats.fetch_tlbhit++;
    immu_stats.fetch_tlbhit++;
    TRACE("ITLB hit (virtaddr=%"PRIxADDR").\n", virtaddr);
    TRACE("ITLB hit (virtaddr=%"PRIxADDR").\n", virtaddr);
 
 
 
    itlbtr = itlbmr + 128;
 
 
    /* Set LRUs */
    /* Set LRUs */
    for (i = 0; i < config.immu.nways; i++) {
    for(i = 0; i < config.immu.nways; i++, itlbmr_lru += (128 * 2)) {
      uorreg_t lru = cpu_state.sprs[SPR_ITLBMR_BASE(i) + set];
      if(*itlbmr_lru & SPR_ITLBMR_LRU)
      if (lru & SPR_ITLBMR_LRU) {
        *itlbmr_lru = (*itlbmr_lru & ~SPR_ITLBMR_LRU) |
        lru = (lru & ~SPR_ITLBMR_LRU) | ((lru & SPR_ITLBMR_LRU) - 0x40);
                                        ((*itlbmr_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] |= (config.immu.nsets - 1) << 6;
    /* 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
 
     * as such lru_reload has all bits set that get touched during decrementing
 
     * SPR_DTLBMR_LRU */
 
    *itlbmr |= config.immu.lru_reload;
 
 
    /* Check if page is cache inhibited */
    /* Check if page is cache inhibited */
    insn_ci = (cpu_state.sprs[SPR_ITLBTR_BASE(way) + set] & SPR_ITLBTR_CI) == SPR_ITLBTR_CI;
    insn_ci = *itlbtr & SPR_ITLBTR_CI;
 
 
    runtime.sim.mem_cycles += config.immu.hitdelay;
    runtime.sim.mem_cycles += config.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 (!(cpu_state.sprs[SPR_ITLBTR_BASE(way) + set] & SPR_ITLBTR_SXE))
      if (!(*itlbtr & SPR_ITLBTR_SXE))
        except_handle(EXCEPT_IPF, virtaddr);
        except_handle(EXCEPT_IPF, virtaddr);
    } else {
    } else {
      if (!(cpu_state.sprs[SPR_ITLBTR_BASE(way) + set] & SPR_ITLBTR_UXE))
      if (!(*itlbtr & SPR_ITLBTR_UXE))
        except_handle(EXCEPT_IPF, virtaddr);
        except_handle(EXCEPT_IPF, virtaddr);
    }
    }
 
 
    ppn = cpu_state.sprs[SPR_ITLBTR_BASE(way) + set] / config.immu.pagesize;
    TRACE("Returning physical address %"PRIxADDR"\n",
    return (ppn * config.immu.pagesize) + (virtaddr % config.immu.pagesize);
          (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr &
 
                                               (config.immu.page_offset_mask)));
 
    return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr &
 
                                                (config.immu.page_offset_mask));
  }
  }
  else {  /* No, we didn't. */
 
 
  /* No, we didn't. */
    immu_stats.fetch_tlbmiss++;
    immu_stats.fetch_tlbmiss++;
#if 0
#if 0
    for (i = 0; i < config.immu.nways; i++)
    for (i = 0; i < config.immu.nways; i++)
      if (((cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_LRU) >> 6) < minlru)
      if (((cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_LRU) >> 6) < minlru)
        minway = i;
        minway = i;
Line 132... Line 165...
    runtime.sim.mem_cycles += config.immu.missdelay;
    runtime.sim.mem_cycles += config.immu.missdelay;
 
 
    except_handle(EXCEPT_ITLBMISS, virtaddr);
    except_handle(EXCEPT_ITLBMISS, virtaddr);
    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).
 *
 *
Line 146... Line 178...
 *       else      - appropriate PA (note it IMMU is not present
 *       else      - appropriate PA (note it IMMU is not present
 *                   PA === EA)
 *                   PA === EA)
 */
 */
oraddr_t peek_into_itlb(oraddr_t virtaddr)
oraddr_t peek_into_itlb(oraddr_t virtaddr)
{
{
  int set, way = -1;
  uorreg_t *itlbmr;
  int i;
  uorreg_t *itlbtr;
  oraddr_t tagaddr;
  uorreg_t *itlbmr_lru;
  oraddr_t vpn, ppn;
 
 
 
  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);
  }
  }
 
 
  /* Which set to check out? */
  itlbmr = immu_find_tlbmr(virtaddr, &itlbmr_lru);
  set = (virtaddr / config.immu.pagesize) % config.immu.nsets;
 
  tagaddr = (virtaddr / config.immu.pagesize) / config.immu.nsets;
 
  vpn = virtaddr / (config.immu.pagesize * config.immu.nsets);
 
 
 
  /* Scan all ways and try to find a matching way. */
 
  for (i = 0; i < config.immu.nways; i++)
 
    if (((cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] / (config.immu.pagesize * config.immu.nsets)) == vpn) &&
 
        (cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_V))
 
      way = i;
 
 
 
  /* Did we find our tlb entry? */
  /* Did we find our tlb entry? */
  if (way >= 0) { /* Yes, we did. */
  if(itlbmr) { /* Yes, we did. */
 
    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 (!(cpu_state.sprs[SPR_ITLBTR_BASE(way) + set] & SPR_ITLBTR_SXE)) {
      if (!(*itlbtr & SPR_ITLBTR_SXE)) {
        /* no luck, giving up */
        /* no luck, giving up */
        return(0);
        return(0);
      }
      }
    } else {
    } else {
      if (!(cpu_state.sprs[SPR_ITLBTR_BASE(way) + set] & SPR_ITLBTR_UXE)) {
      if (!(*itlbtr & SPR_ITLBTR_UXE)) {
        /* no luck, giving up */
        /* no luck, giving up */
        return(0);
        return(0);
      }
      }
    }
    }
 
 
    ppn = cpu_state.sprs[SPR_ITLBTR_BASE(way) + set] / config.immu.pagesize;
    return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr &
    return (ppn * config.immu.pagesize) + (virtaddr % config.immu.pagesize);
                                                (config.immu.page_offset_mask));
  }
 
  else {
 
    return(0);
 
  }
  }
 
 
  ERR("should never have happened\n");
 
  return(0);
  return(0);
}
}
 
 
 
 
oraddr_t immu_translate(oraddr_t virtaddr)
 
{
 
  oraddr_t phyaddr = immu_simulate_tlb(virtaddr);
 
 
 
/*  PRINTF("IMMU translate(%x) = %x\n", virtaddr, phyaddr);*/
 
  return phyaddr;
 
}
 
 
 
void itlb_info(void)
void itlb_info(void)
{
{
  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;

powered by: WebSVN 2.1.0

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