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

📄 arm7_mmu.cpp

📁 浙江大学的悟空嵌入式系统模拟器
💻 CPP
字号:
/*
 *  Copyright (c) 2005 Zhejiang University, P.R.China
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */ 

//=============================================================================
/**
 *  \file    ARM/ARM7_MMU.cpp
 *
 *  $Id: ARM7_MMU.cpp,v 1.2 2005/06/15 12:50:42 jiajc Exp $
 *
 *  \author  Juncheng Jia <jiajuncheng@gmail.com>
 */
//=============================================================================

//#include "stdafx.h"
#include "arm7_mmu.h"

namespace ARM {

ARM7_MMU::ARM7_MMU(void)
{
	cache_ = new Cache(*this, 16, 4, 128, Cache::WRITE_THROUGH);
	tlb_ = new TLB(*this, 64);
}

ARM7_MMU::~ARM7_MMU(void)
{
	delete tlb_;
	delete cache_;
}

Memory_Result ARM7_MMU::data_read(u32 start, size_t size, Bytecode_Type & buffer)
{
	if( ! is_enable() )
	{
		// ! NOTICE: THERE IS NO SIZE CHECK NOW !!!
		return mem_access(Memory_32Bit::MEMORY_READ, start, size, buffer);
	}

	// check for align fault
	if ((start & 3) && (size == 4) && align_fault_check_on() || \
	    (start & 1) && (size == 2) && align_fault_check_on() ) 
	{ 
		WUKONG_STDOUT <<"ALIGNMENT_FAULT" << std::endl;
		set_fault_status(ALIGNMENT_FAULT);
		set_fault_address(start);
		return ACCESS_FAULT;	
	}

	if ( cache_on() )
	{
		Cache::Cache_Line * cache_line = cache_->search(start);
		if (cache_line)
		{
			size_t t = start & ( cache_->get_width() -1 );
			for (size_t i = 0; i < size; i++, t++)
			{
				buffer.push_back(cache_line->data[t]);
			}
			return ACCESS_SUCCESSFUL;
		}
	}
	
	TLB::Entry * tlb = NULL;

	if( tlb_->ttw(start, &tlb) == ACCESS_FAULT)
	{
		return ACCESS_FAULT;
	}

	if( tlb_->check_access(start, tlb, true) == ACCESS_FAULT)
	{
		return ACCESS_FAULT;
	}

	u32 pa = (tlb->pa & TLB::masks [tlb->mapping]) |
		(start & ~TLB::masks[tlb->mapping]);

	if ((tlb->perms & 0x08) && cache_on() )
	{
		Cache::Cache_Line * cache_line;
		cache_line = cache_->allocate(start, 0);

		u32 fetch;
		fetch = pa & 0xFFFFFFF0;

		mem_access(Memory_32Bit::MEMORY_READ, fetch, cache_->get_width()  , cache_line->data);

		cache_line->tag = cache_->get_tag(start) | Cache::TAG_VALID_FLAG;

		size_t t = start & ( cache_->get_width()  -1 );
		for (size_t i = 0; i < size; i++, t++)
		{
			buffer.push_back(cache_line->data[t]);
		}
	}
	else
	{
		if( size == 1 || size ==  2 || size == 4)
		{
			mem_access(Memory_32Bit::MEMORY_READ, pa, size, buffer);
			return ACCESS_SUCCESSFUL;
		}
		else
		{
			return ACCESS_FAULT;
		}
	}
	

	return ACCESS_SUCCESSFUL;
}

Memory_Result ARM7_MMU::data_write(u32 start, size_t size, Bytecode_Type & buffer)
{

	if( ! is_enable()  )
	{
		// ! NOTICE: THERE IS NO SIZE CHECK NOW !!!
		return mem_access(Memory_32Bit::MEMORY_WRITE, start, size, buffer);
	}
	
	if ((start & 3) && (size == 4) && align_fault_check_on() || \
		(start & 1) && (size == 2) && align_fault_check_on()) 
	{ 
		set_fault_status(ALIGNMENT_FAULT);
		set_fault_address(start);
		return ALIGNMENT_FAULT;
	}

	if ( cache_on() )
	{
		Cache::Cache_Line * cache_line = cache_->search(start);
		if (cache_line)
		{
			size_t t = start  & ( cache_->get_width()  - 1);
			for (size_t i = 0; i < size; i++, t++)
			{
				cache_line->data[t] = buffer[i];
			}
		}
	}

	TLB::Entry * tlb = NULL;

	if( tlb_->ttw(start, &tlb) == ACCESS_FAULT)
	{
 		return ACCESS_FAULT;
	}

	if( tlb_->check_access(start, tlb, false) == ACCESS_FAULT)
	{
		return ACCESS_FAULT;
	}

	u32 pa = (tlb->pa & TLB::masks[tlb->mapping]) |
		(start & ~TLB::masks[tlb->mapping]);

	if( size == 1 || size ==  2 || size == 4)
	{
		mem_access(Memory_32Bit::MEMORY_WRITE, pa, size, buffer);
		return ACCESS_SUCCESSFUL;
	}
	else
	{
		return ACCESS_FAULT;
	}	
	return ACCESS_SUCCESSFUL;
}

Memory_Result ARM7_MMU::instr_read(u32 start, size_t size, Bytecode_Type & buffer)
{
	return data_read(start, WORD_SIZE, buffer);
}

ARM7_CP15::ARM7_CP15(u32 id_code) : CP15( id_code )
{

}

ARM7_CP15::~ARM7_CP15()
{

}

CPU_720T * ARM7_CP15::get_cpu()
{
	return (CPU_720T *)Core::Wukong_Get_System().get_cpu();
}

ARM7_MMU * ARM7_CP15::get_mmu()
{
	return (ARM7_MMU *)(& get_cpu()->get_mmu());
}

void ARM7_CP15::on_create()
{
	Core::Processor::Config config;
	config.name = "CP15";
	config.family = "CP_FAMILY";
	for(Core::u32 i = 0; i < 17; ++i)
	{
		Core::Register_File::append_profile(config.register_config, \
			CP15::reg_name_[i], Core::Register_File::REGISTER_32BIT);
	}
	configurate(config);


	// disable MMU
	write_register(CONTROL,0x00000070);
	write_register(ID_CODE,id_code_);
}

void ARM7_CP15::on_reset()
{
	write_register(CONTROL,0x00000070);
}

void ARM7_CP15::MCR(Core::Instruction_Unit binary)
{
	Binary_32Bit bits(binary);
	u32 opcode1 = bits.convert_to_int(21, 23);
	u32 CRn = bits.convert_to_int(16,19);
	u32 Rd = bits.convert_to_int(12, 15);
	u32 opcode2 = bits.convert_to_int(5, 7);
	u32 CRm = bits.convert_to_int(0, 3);

	if( opcode1 != 0 || Rd == 15 )
	{
		return;
	}

	u32 value;
	get_cpu()->read_register(Rd, value);

	switch( CRn )
	{
	case 0:
		if( opcode2 == 0 )
			write_register(ID_CODE, value);
		else if( opcode2 == 1)
			write_register(CACHE_TYPE, value);
		break;
	case 1:
		write_register(CONTROL, value);
		break;
	case 2:
		write_register(TRANSLATION_TABLE_BASE, value);
		break;
	case 3:
		write_register(DOMAIN, value);
		break;
	case 5:
		write_register(FAULT_STATUS, value);
		break;
	case 6:
		write_register(FAULT_ADDRESS, value);
		break;
	case 7:
		if( opcode2 == 0 )
			get_mmu()->cache_->invalidate_all();
		break;
	case 8:
		if ( opcode2 == 0 )
			get_mmu()->tlb_->invalidate_all();
		else if ( opcode2 == 1)
			get_mmu()->tlb_->invalidate(value);
		break;
	default:
		assert(0);
	}

}

void ARM7_CP15::MRC(Core::Instruction_Unit binary)
{
	Binary_32Bit bits(binary);
	u32 opcode1 = bits.convert_to_int(21, 23);
	u32 CRn = bits.convert_to_int(16,19);
	u32 Rd = bits.convert_to_int(12, 15);
	u32 opcode2 = bits.convert_to_int(5, 7);
	u32 CRm = bits.convert_to_int(0, 3);
	
	if( opcode1 != 0 || Rd == 15 || CRm != 0) 
	{
		return ;
	}

	u32 value;

	switch( CRn )
	{
	case 0:
		if( opcode2 == 0 )
			read_register(ID_CODE, value);
		else if( opcode2 == 1)
			read_register(CACHE_TYPE, value);

		break;
	case 1:
		read_register(CONTROL, value);
		break;
	case 2:
		read_register(TRANSLATION_TABLE_BASE, value);
		break;
	case 3:
		read_register(DOMAIN, value);
		break;
	case 5:
		read_register(FAULT_STATUS, value);
		break;
	case 6:
		read_register(FAULT_ADDRESS, value);
		break;
	default:
		assert(0);
	}

	get_cpu()->write_register(Rd, value);	

}


} // namespace

⌨️ 快捷键说明

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