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

📄 arm920t_mmu.c

📁 这是Skyeye 0.9 版本的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
    arm920t_mmu.c - ARM920T Memory Management Unit emulation.
    Copyright (C) 2003 Skyeye Develop Group
    for help please send mail to <skyeye-developer@lists.gro.clinux.org>

    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"

#define ARM920T_I_TLB() (&state->mmu.u.arm920t_mmu.i_tlb)
#define ARM920T_I_CACHE() (&state->mmu.u.arm920t_mmu.i_cache)

#define ARM920T_D_TLB() (&state->mmu.u.arm920t_mmu.d_tlb)
#define ARM920T_D_CACHE() (&state->mmu.u.arm920t_mmu.d_cache)
#define ARM920T_WB() (&state->mmu.u.arm920t_mmu.wb_t)

typedef struct arm920t_mmu_desc_s
{
  int i_tlb;
  cache_desc_t i_cache;

  int d_tlb;
  cache_desc_t d_cache;
  wb_desc_t wb;
} arm920t_mmu_desc_t;

static arm920t_mmu_desc_t arm920t_mmu_desc = {
  64,
  /* 32 bytes per line
   * 64 way
   * 8 set
   * */
  {32, 64, 8, CACHE_WRITE_BACK},

  64,
  {32, 64, 8, CACHE_WRITE_BACK},
  {8, 8}			//for byte size
};

static fault_t arm920t_mmu_write (ARMul_State * state, ARMword va,
				  ARMword data, ARMword datatype);
static fault_t arm920t_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
arm920t_mmu_init (ARMul_State * state)
{
  arm920t_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 = &arm920t_mmu_desc;
  if (mmu_tlb_init (ARM920T_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 (ARM920T_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 (ARM920T_D_TLB (), desc->d_tlb))
    {
      err_msg ("d_tlb init %d\n", -1);
      goto d_tlb_init_error;
    }

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

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

wb_init_error:
  mmu_cache_exit (ARM920T_D_CACHE ());
d_cache_init_error:
  mmu_tlb_exit (ARM920T_D_TLB ());
d_tlb_init_error:
  mmu_cache_exit (ARM920T_I_CACHE ());
i_cache_init_error:
  mmu_tlb_exit (ARM920T_I_TLB ());
i_tlb_init_error:
  return -1;
}

void
arm920t_mmu_exit (ARMul_State * state)
{
  mmu_wb_exit (ARM920T_WB ());
  mmu_cache_exit (ARM920T_D_CACHE ());
  mmu_tlb_exit (ARM920T_D_TLB ());
  mmu_cache_exit (ARM920T_I_CACHE ());
  mmu_tlb_exit (ARM920T_I_TLB ());
};


static fault_t
arm920t_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, ARM920T_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, ARM920T_I_CACHE (), va);
  if (cache)
    {
      *instr = cache->data[va_cache_index (va, ARM920T_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, ARM920T_I_CACHE (), va, pa);
      index = va_cache_index (va, ARM920T_I_CACHE ());
      *instr = cache->data[va_cache_index (va, ARM920T_I_CACHE ())];
    }
  else
    *instr = mem_read_word (state, pa);

  return 0;
};



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

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

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




static fault_t
arm920t_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
		  ARMword datatype)
{
  fault_t fault;
  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 arm920t_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, ARM920T_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 main cache */
  cache = mmu_cache_search (state, ARM920T_D_CACHE (), va);
  if (cache)
    {
      *data = cache->data[va_cache_index (va, ARM920T_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, ARM920T_D_CACHE(), pa);
	  //}
	  mmu_cache_soft_flush (state, ARM920T_D_CACHE (), pa);
	}
      return 0;
    }

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

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

      //if (tlb_b_flag(tlb))
      cache_t = ARM920T_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 arm920t_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:
//      printf("va: %x, pa:%x data: %x\n", va, pa, *data);
  return 0;
}


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

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

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



static fault_t
arm920t_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);
  va = mmu_pid_va_map (va);
  real_va = va;

  /*search instruction cache */
  cache = mmu_cache_search (state, ARM920T_I_CACHE (), va);
  if (cache)
    {
      update_cache (state, va, data, datatype, cache, ARM920T_I_CACHE (),
		    real_va);
    }

  if (MMU_Disabled)
    {
      //mem_write_word(state, va, data);
      if (datatype == ARM_BYTE_TYPE)
	mem_write_byte (state, va, data);
      else if (datatype == ARM_HALFWORD_TYPE)
	mem_write_halfword (state, va, data);
      else if (datatype == ARM_WORD_TYPE)
	mem_write_word (state, va, data);
      else
	{
	  printf ("SKYEYE:1 arm920t_mmu_write error: unknown data type %d\n",
		  datatype);
	  exit (-1);
	}

      return 0;
    }
  /*align check */
  //if ((va & (WORD_SIZE - 1)) && MMU_Aligned){
  if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
      ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned))

⌨️ 快捷键说明

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