⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sa_mmu.c

📁 这是Skyeye 0.9 版本的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
    armmmu.c - Memory Management Unit emulation.
    ARMulator extensions for the ARM7100 family.
    Copyright (C) 1999  Ben Williamson

    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 Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <assert.h>
#include <string.h>
#include "armdefs.h"

typedef struct sa_mmu_desc_s
{
  int i_tlb;
  cache_desc_t i_cache;

  int d_tlb;
  cache_desc_t main_d_cache;
  cache_desc_t mini_d_cache;
  int rb;
  wb_desc_t wb;
} sa_mmu_desc_t;

static sa_mmu_desc_t sa11xx_mmu_desc = {
  32,
  {32, 32, 16, CACHE_WRITE_BACK},

  32,
  {32, 32, 8, CACHE_WRITE_BACK},
  {32, 2, 8, CACHE_WRITE_BACK},
  4,
  //{8, 4},  for word size 
  {8, 16},			//for byte size,   chy 2003-07-11
};

static fault_t sa_mmu_write (ARMul_State * state, ARMword va, ARMword data,
			     ARMword datatype);
static fault_t sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
			    ARMword datatype);
static fault_t update_cache (ARMul_State * state, ARMword va, ARMword data,
			     ARMword datatype, cache_line_t * cache,
			     cache_t * cache_t, ARMword real_va);

int
sa_mmu_init (ARMul_State * state)
{
  sa_mmu_desc_t *desc;
  cache_desc_t *c_desc;

  state->mmu.control = 0x70;
  state->mmu.translation_table_base = 0xDEADC0DE;
  state->mmu.domain_access_control = 0xDEADC0DE;
  state->mmu.fault_status = 0;
  state->mmu.fault_address = 0;
  state->mmu.process_id = 0;

  desc = &sa11xx_mmu_desc;
  if (mmu_tlb_init (I_TLB (), desc->i_tlb))
    {
      err_msg ("i_tlb init %d\n", -1);
      goto i_tlb_init_error;
    }

  c_desc = &desc->i_cache;
  if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way,
		      c_desc->set, c_desc->w_mode))
    {
      err_msg ("i_cache init %d\n", -1);
      goto i_cache_init_error;
    }

  if (mmu_tlb_init (D_TLB (), desc->d_tlb))
    {
      err_msg ("d_tlb init %d\n", -1);
      goto d_tlb_init_error;
    }

  c_desc = &desc->main_d_cache;
  if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way,
		      c_desc->set, c_desc->w_mode))
    {
      err_msg ("main_d_cache init %d\n", -1);
      goto main_d_cache_init_error;
    }

  c_desc = &desc->mini_d_cache;
  if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way,
		      c_desc->set, c_desc->w_mode))
    {
      err_msg ("mini_d_cache init %d\n", -1);
      goto mini_d_cache_init_error;
    }

  if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb))
    {
      err_msg ("wb init %d\n", -1);
      goto wb_init_error;
    }

  if (mmu_rb_init (RB (), desc->rb))
    {
      err_msg ("rb init %d\n", -1);
      goto rb_init_error;
    }
  return 0;

rb_init_error:
  mmu_wb_exit (WB ());
wb_init_error:
  mmu_cache_exit (MINI_D_CACHE ());
mini_d_cache_init_error:
  mmu_cache_exit (MAIN_D_CACHE ());
main_d_cache_init_error:
  mmu_tlb_exit (D_TLB ());
d_tlb_init_error:
  mmu_cache_exit (I_CACHE ());
i_cache_init_error:
  mmu_tlb_exit (I_TLB ());
i_tlb_init_error:
  return -1;
}

void
sa_mmu_exit (ARMul_State * state)
{
  mmu_rb_exit (RB ());
  mmu_wb_exit (WB ());
  mmu_cache_exit (MINI_D_CACHE ());
  mmu_cache_exit (MAIN_D_CACHE ());
  mmu_tlb_exit (D_TLB ());
  mmu_cache_exit (I_CACHE ());
  mmu_tlb_exit (I_TLB ());
};


static fault_t
sa_mmu_load_instr (ARMul_State * state, ARMword va, ARMword * instr)
{
  fault_t fault;
  tlb_entry_t *tlb;
  cache_line_t *cache;
  int c;			//cache bit
  ARMword pa;			//physical addr

  static int debug_count = 0;	//used for debug

  d_msg ("va = %x\n", va);

  va = mmu_pid_va_map (va);
  if (MMU_Enabled)
    {
      /*align check */
      if ((va & (WORD_SIZE - 1)) && MMU_Aligned)
	{
	  d_msg ("align\n");
	  return ALIGNMENT_FAULT;
	}
      else
	va &= ~(WORD_SIZE - 1);

      /*translate tlb */
      fault = translate (state, va, I_TLB (), &tlb);
      if (fault)
	{
	  d_msg ("translate\n");
	  return fault;
	}

      /*check access */
      fault = check_access (state, va, tlb, 1);
      if (fault)
	{
	  d_msg ("check_fault\n");
	  return fault;
	}
    }

  /*search cache no matter MMU enabled/disabled */
  cache = mmu_cache_search (state, I_CACHE (), va);
  if (cache)
    {
      *instr = cache->data[va_cache_index (va, I_CACHE ())];
      return 0;
    }

  /*if MMU disabled or C flag is set alloc cache */
  if (MMU_Disabled)
    {
      c = 1;
      pa = va;
    }
  else
    {
      c = tlb_c_flag (tlb);
      pa = tlb_va_to_pa (tlb, va);
    }

  if (c)
    {
      int index;

      debug_count++;
      cache = mmu_cache_alloc (state, I_CACHE (), va, pa);
      index = va_cache_index (va, I_CACHE ());
      *instr = cache->data[va_cache_index (va, I_CACHE ())];
    }
  else
    *instr = mem_read_word (state, pa);

  return 0;
};



static fault_t
sa_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data)
{
  //ARMword temp,offset;
  fault_t fault;
  fault = sa_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE);
  return fault;
}

static fault_t
sa_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data)
{
  //ARMword temp,offset;
  fault_t fault;
  fault = sa_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE);
  return fault;
}

static fault_t
sa_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data)
{
  return sa_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);
}




static fault_t
sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
	     ARMword datatype)
{
  fault_t fault;
  rb_entry_t *rb;
  tlb_entry_t *tlb;
  cache_line_t *cache;
  ARMword pa, real_va, temp, offset;

  d_msg ("va = %x\n", va);

  va = mmu_pid_va_map (va);
  real_va = va;
  /*if MMU disabled, memory_read */
  if (MMU_Disabled)
    {
      //*data = mem_read_word(state, va);
      if (datatype == ARM_BYTE_TYPE)
	*data = mem_read_byte (state, va);
      else if (datatype == ARM_HALFWORD_TYPE)
	*data = mem_read_halfword (state, va);
      else if (datatype == ARM_WORD_TYPE)
	*data = mem_read_word (state, va);
      else
	{
	  printf ("SKYEYE:1 sa_mmu_read error: unknown data type %d\n",
		  datatype);
	  exit (-1);
	}

      return 0;
    }

  /*align check */
  if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
      ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned))
    {
      d_msg ("align\n");
      return ALIGNMENT_FAULT;
    }				// else

  va &= ~(WORD_SIZE - 1);

  /*translate va to tlb */
  fault = translate (state, va, D_TLB (), &tlb);
  if (fault)
    {
      d_msg ("translate\n");
      return fault;
    }
  /*check access permission */
  fault = check_access (state, va, tlb, 1);
  if (fault)
    return fault;
  /*search in read buffer */
  rb = mmu_rb_search (RB (), va);
  if (rb)
    {
      if (rb->fault)
	return rb->fault;
      *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT];
      goto datatrans;
      //return 0;
    };
  /*search main cache */
  cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
  if (cache)
    {
      *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())];
      goto datatrans;
      //return 0;
    }
  /*search mini cache */
  cache = mmu_cache_search (state, MINI_D_CACHE (), va);
  if (cache)
    {
      *data = cache->data[va_cache_index (va, MINI_D_CACHE ())];
      goto datatrans;
      //return 0;
    }

  /*get phy_addr */
  pa = tlb_va_to_pa (tlb, va);
  if ((pa >= 0xe0000000) && (pa < 0xe8000000))
    {
      if (tlb_c_flag (tlb))
	{
	  if (tlb_b_flag (tlb))
	    {
	      mmu_cache_soft_flush (state, MAIN_D_CACHE (), pa);
	    }
	  else
	    {
	      mmu_cache_soft_flush (state, MINI_D_CACHE (), pa);
	    }
	}
      return 0;
    }

  /*if Buffer, drain Write Buffer first */
  if (tlb_b_flag (tlb))
    mmu_wb_drain_all (state, WB ());

  /*alloc cache or mem_read */
  if (tlb_c_flag (tlb) && MMU_DCacheEnabled)
    {
      cache_t *cache_t;

      if (tlb_b_flag (tlb))
	cache_t = MAIN_D_CACHE ();
      else
	cache_t = MINI_D_CACHE ();
      cache = mmu_cache_alloc (state, cache_t, va, pa);
      *data = cache->data[va_cache_index (va, cache_t)];
    }
  else
    {
      //*data = mem_read_word(state, pa);
      if (datatype == ARM_BYTE_TYPE)
	*data = mem_read_byte (state, pa | (real_va & 3));
      else if (datatype == ARM_HALFWORD_TYPE)
	*data = mem_read_halfword (state, pa | (real_va & 2));
      else if (datatype == ARM_WORD_TYPE)
	*data = mem_read_word (state, pa);
      else
	{
	  printf ("SKYEYE:2 sa_mmu_read error: unknown data type %d\n",
		  datatype);
	  exit (-1);
	}
      return 0;
    }


datatrans:
  if (datatype == ARM_HALFWORD_TYPE)
    {
      temp = *data;
      offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3;	/* bit offset into the word */
      *data = (temp >> offset) & 0xffff;
    }
  else if (datatype == ARM_BYTE_TYPE)
    {
      temp = *data;
      offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3;	/* bit offset into the word */
      *data = (temp >> offset & 0xffL);
    }
end:
  return 0;
}


static fault_t
sa_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data)
{
  return sa_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);
}

static fault_t
sa_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data)
{
  return sa_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);
}

static fault_t
sa_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data)
{
  return sa_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);
}



static fault_t
sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, ARMword datatype)
{
  tlb_entry_t *tlb;
  cache_line_t *cache;
  int b;
  ARMword pa, real_va;
  fault_t fault;

  d_msg ("va = %x, val = %x\n", va, data);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -