📄 xscale_mmu.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/XScale_MMU.h
*
* $Id: XScale_MMU.cpp,v 1.2 2005/06/15 12:50:42 jiajc Exp $
*
* \author Juncheng Jia <jiajuncheng@gmail.com>
*/
//=============================================================================
#include "XScale_MMU.h"
namespace ARM {
XScale_MMU::XScale_MMU()
{
instr_tlb_ = new TLB(*this, 32);
data_tlb_ = new TLB(*this, 32);
}
XScale_MMU::~XScale_MMU(void)
{
delete instr_tlb_;
delete data_tlb_;
}
u32 XScale_MMU::get_mva(u32 va)
{
return va;
if ( va & PID_MAP_MASK)
{
return va;
}
else
{
u32 value;
get_cp15()->read_register(CP15::PROCESS_ID, value);
return va | (value & PID_MAP_MASK);
}
}
Memory_Result XScale_MMU::instr_read(u32 start, size_t size, Bytecode_Type & buffer)
{
start = get_mva(start);
if( is_enable())
{
if( ( start & ( WORD_SIZE - 1)) && align_fault_check_on())
{
WUKONG_STDOUT <<"ALIGNMENT_FAULT" << std::endl;
set_fault_status(ALIGNMENT_FAULT);
set_fault_address(start);
return ACCESS_FAULT;
}
else
{
start &= ~(WORD_SIZE -1);
}
TLB::Entry * tlb = NULL;
if( instr_tlb_->ttw(start, &tlb) == ACCESS_FAULT)
{
return ACCESS_FAULT;
}
if( instr_tlb_->check_access(start, tlb, true) == ACCESS_FAULT)
{
return ACCESS_FAULT;
}
start = instr_tlb_->get_pa(tlb, start);
}
return mem_access(Memory_32Bit::MEMORY_READ, start, size,buffer);
}
Memory_Result XScale_MMU::data_read(u32 start, size_t size, Bytecode_Type & buffer)
{
start = get_mva(start);
if( is_enable())
{
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;
}
TLB::Entry * tlb = NULL;
if( data_tlb_->ttw(start, &tlb) == ACCESS_FAULT)
{
return ACCESS_FAULT;
}
if( data_tlb_->check_access(start, tlb, true) == ACCESS_FAULT)
{
return ACCESS_FAULT;
}
start = data_tlb_->get_pa(tlb, start);
}
mem_access(Memory_32Bit::MEMORY_READ, start, size,buffer);
return ACCESS_SUCCESSFUL;
}
Memory_Result XScale_MMU::data_write(u32 start, size_t size, Bytecode_Type & buffer)
{
start = get_mva(start);
if( is_enable())
{
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;
}
TLB::Entry * tlb = NULL;
if( data_tlb_->ttw(start, &tlb) == ACCESS_FAULT)
{
return ACCESS_FAULT;
}
if( data_tlb_->check_access(start, tlb, false) == ACCESS_FAULT)
{
return ACCESS_FAULT;
}
start = data_tlb_->get_pa(tlb, start);
}
mem_access(Memory_32Bit::MEMORY_WRITE, start, size,buffer);
return ACCESS_SUCCESSFUL;
}
XScale_CP15::XScale_CP15(u32 id) : CP15( id )
{
}
XScale_CP15::~XScale_CP15()
{
}
Core::CPU_32Bit * XScale_CP15::get_cpu()
{
return (Core::CPU_32Bit *)Core::Wukong_Get_System().get_cpu();
}
XScale_MMU * XScale_CP15::get_mmu()
{
return (XScale_MMU *)(& get_cpu()->get_mmu());
}
void XScale_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 XScale_CP15::on_reset()
{
write_register(CONTROL,0x00000070);
}
void XScale_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()->instr_tlb_->invalidate_all();
get_mmu()->data_tlb_->invalidate_all();
}
else if ( opcode2 == 1)
{
get_mmu()->instr_tlb_->invalidate(value);
get_mmu()->data_tlb_->invalidate(value);
}
break;
if ( opcode2 == BINARY4(0000) && CRm == BINARY4(0111) )
{
get_mmu()->instr_tlb_->invalidate_all();
get_mmu()->data_tlb_->invalidate_all();
}
else if ( opcode2 == BINARY4(0000) && CRm == BINARY4(0101) )
{
get_mmu()->instr_tlb_->invalidate_all();
}
else if ( opcode2 == BINARY4(0001) && CRm == BINARY4(0101))
{
get_mmu()->instr_tlb_->invalidate(value);
}
else if ( opcode2 == BINARY4(0000) && CRm == BINARY4(0110))
{
get_mmu()->data_tlb_->invalidate_all();
}
else if ( opcode2 ==BINARY4(0001) && CRm == BINARY4(0110))
{
get_mmu()->data_tlb_->invalidate(value);
}
break;
case 13:
value &= MMU::PID_MAP_MASK;
write_register(PROCESS_ID, value);
break;
case 15:
value &= 0x3fff;
write_register(COPROCESSOR_ACCESS, value);
break;
default:
assert(0);
}
}
void XScale_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;
case 13:
read_register(PROCESS_ID, value);
break;
case 15:
read_register(COPROCESSOR_ACCESS, value);
break;
default:
assert(0);
}
get_cpu()->write_register(Rd, value);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -