📄 arm7_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/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 + -