Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / cpu / src / SS_AsiSpace.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: SS_AsiSpace.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named 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 work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
#include "SS_AsiSpace.h"
#include "SS_Strand.h"
#include "SS_AsiCtrReg.h"
#include <stdio.h>
#include <stdlib.h>
#include <new>
SS_AsiSpace::SS_AsiSpace()/*{{{*/
:
mask(~SS_Vaddr(0)),
fail(0,mask,0,0,no_rd,no_wr,no_rd,no_wr),
table(0),
table_copy(false),
block(0),
free_range_index(ALLOC),
alloc(0),
size(0),
asi(0)
{}
/*}}}*/
SS_AsiSpace::~SS_AsiSpace()/*{{{*/
{
if (table) free(table);
while (block)
{
Block* p = block;
block = p->next;
delete p;
}
}
/*}}}*/
SS_AsiSpace::Error SS_AsiSpace::no_rd( SS_Node*, void*, SS_Strand*, SS_Vaddr, uint64_t* )/*{{{*/
{
return SS_AsiSpace::NO_READ;
}
/*}}}*/
SS_AsiSpace::Error SS_AsiSpace::no_wr( SS_Node*, void*, SS_Strand*, SS_Vaddr, uint64_t )/*{{{*/
{
return SS_AsiSpace::NO_WRITE;
}
/*}}}*/
SS_AsiSpace::Error SS_AsiSpace::ld64( SS_Strand* s, SS_Vaddr addr, uint64_t* data )/*{{{*/
{
addr &= mask;
Range* r = find(addr);
return (r->ld)(r->obj,r->reg,s,addr,data);
}
/*}}}*/
SS_AsiSpace::Error SS_AsiSpace::st64( SS_Strand* s, SS_Vaddr addr, uint64_t data )/*{{{*/
{
addr &= mask;
Range* r = find(addr);
return (r->st)(r->obj,r->reg,s,addr,data);
}
/*}}}*/
SS_AsiSpace::Error SS_AsiSpace::rd64( SS_Strand* s, SS_Vaddr addr, uint64_t* data )/*{{{*/
{
addr &= mask;
Range* r = find(addr);
return (r->rd)(r->obj,r->reg,s,addr,data);
}
/*}}}*/
SS_AsiSpace::Error SS_AsiSpace::wr64( SS_Strand* s, SS_Vaddr addr, uint64_t data )/*{{{*/
{
addr &= mask;
Range* r = find(addr);
return (r->wr)(r->obj,r->reg,s,addr,data);
}
/*}}}*/
void SS_AsiSpace::merge( SS_AsiSpace& asi_space )/*{{{*/
{
if (asi_space.size)
{
// If there is ranges defined in this space then we need to
// do some merging. If this is the first merge then we assume
// that the ranges associated with this ASI are defined at one
// level (SS_Node) only. If so then we can do a cheap copy.
// Else we need to do a quick copy and poper insert the rest
mask &= asi_space.mask;
if (size == 0) // do cheap copy first
{
alloc = asi_space.alloc;
size = asi_space.size;
table = asi_space.table;
table_copy = true;
}
else
{
if (table_copy) // real copy first, then insert proper
{
Range** old_table = table;
table = (Range**)malloc(sizeof(Range*) * alloc);
for (uint_t i=0; i < size; i++)
table[i] = old_table[i];
table_copy = false;
}
for (uint_t i=0; i < asi_space.size; i++)
add(asi_space.table[i]);
}
}
}
/*}}}*/
void SS_AsiSpace::add( SS_Vaddr va, SS_Node* obj, SS_AsiCtrReg& reg )/*{{{*/
{
add(va,va,obj,&reg,SS_AsiCtrReg::ld64,SS_AsiCtrReg::st64,SS_AsiCtrReg::rd64,SS_AsiCtrReg::wr64);
}
/*}}}*/
void SS_AsiSpace::add( SS_Vaddr va, SS_Node* obj, SS_SharedAsiCtrReg& reg )/*{{{*/
{
add(va,va,obj,&reg,SS_SharedAsiCtrReg::ld64,SS_SharedAsiCtrReg::st64,
SS_SharedAsiCtrReg::rd64,SS_SharedAsiCtrReg::wr64);
}
/*}}}*/
void SS_AsiSpace::add( SS_Vaddr va, SS_Node* obj, void* reg, Read ld, Write st, Read rd, Write wr )/*{{{*/
{
add(va,va,obj,reg,ld,st,rd,wr);
}
/*}}}*/
void SS_AsiSpace::add( SS_Vaddr lo, SS_Vaddr hi, SS_Node* obj, void* reg, Read ld, Write st, Read rd, Write wr )/*{{{*/
{
if (ld == 0) ld = no_rd;
if (st == 0) st = no_wr;
if (rd == 0) rd = no_rd;
if (wr == 0) wr = no_wr;
if (size == alloc)
{
alloc += ALLOC;
table = (Range**)realloc(table,sizeof(Range*) * alloc);
}
if (free_range_index == ALLOC)
{
// Allocate a new block of Range object. Avoid the C++ constructor
// call as each range will be initialised below anyways.
free_range_index = 0;
Block* new_block = (Block*)malloc(sizeof(Block));
new_block->next = block;
block = new_block;
}
Range* new_range = &block->page[free_range_index++];
new(new_range) Range(lo,hi,obj,reg,ld,st,rd,wr);
add(new_range);
}
/*}}}*/
void SS_AsiSpace::add( Range* new_range )/*{{{*/
{
if (size == alloc)
{
alloc += ALLOC;
table = (Range**)realloc(table,sizeof(Range*) * alloc);
}
SS_Vaddr hi = new_range->hi;
SS_Vaddr lo = new_range->lo;
// Check if we can just append the new range first.
// This will save a lot of time binary searching and
// moving part of the table around.
if ((size == 0) || (table[size - 1]->hi < new_range->lo))
{
table[size] = new_range;
}
else
{
uint_t l = 0;
uint_t h = size;
uint_t m = size >> 1;
Range* r = table[m];
while (l != m)
{
((hi < r->lo) ? h : l) = m;
m = l + ((h - l) >> 1);
r = table[m];
}
if (hi < r->lo)
{
for (uint_t i=size; i > m; i--)
table[i] = table[i-1];
table[m] = new_range;
}
else if (r->hi < lo)
{
for (uint_t i=size; i > (m + 1); i--)
table[i] = table[i-1];
table[m+1] = new_range;
}
else
{
fprintf(stderr,"SS_AsiSpace: asi 0x%x add with lo=0x%llx and hi=0x%llx overlaps with lo=0x%llx and hi=0x%llx\n",asi(),lo,hi,r->lo,r->hi);
exit(-1);
}
}
++size;
}
/*}}}*/