Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / regdef / Block.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: Block.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 "Block.h"
#include "Register.h"
#include "RegisterArray.h"
using namespace std;
static const bool VERBOSE_BLOCK = false;
static const bool VERBOSE_LOOKUP = false;
static const bool VERBOSE_REGISTER = false;
static const bool ASSERT_REGISTER_ERRORS = false;
static const bool MAP_ENABLE = false;
static const bool MAP_CHECK = false;
Block::Block(string n) {
fullName = n;
map = NULL;
final = false;
}
Block::~Block() {
}
void Block::addRegister (Register *r)
{
assert(!final);
regCheck(r);
Addr addr = r->getAddr();
if (addr < minAddr)
minAddr = addr;
if (addr > maxAddr)
maxAddr = addr;
registers.addTail(r);
}
void Block::addRegisterArray (RegisterArray *r)
{
assert(!final);
Addr start = r->getStartAddr();
Addr end = r->getEndAddr();
regArrayCheck(r);
if (start < minAddr)
minAddr = start;
if (end > maxAddr)
maxAddr = end;
registerArrays.addTail(r);
}
void Block::regCheck (Register *r)
{
int errors = 0;
Addr thisAddr = r->getAddr();
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem()) {
Addr regAddr = reg->getAddr();
if (thisAddr == regAddr) {
cerr << "WARNING: " << r->getFullName()
<< " at 0x" << hex << thisAddr
<< " overlaps with " << reg->getFullName()
<< " at 0x" << regAddr << "\n" << dec;
errors++;
}
}
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem()) {
Addr arrayStart = regArray->getStartAddr();
Addr arrayEnd = regArray->getEndAddr();
Addr arrayStep = regArray->getStep();
if (thisAddr >= arrayStart && thisAddr <= arrayEnd &&
((thisAddr - arrayStart) % arrayStep) == 0) {
cerr << "WARNING: " << r->getFullName()
<< " at 0x" << hex << thisAddr
<< " overlaps with " << regArray->getFullName()
<< " at 0x" << arrayStart << " to 0x" << arrayEnd
<< " step 0x" << arrayStep << "\n" << dec;
errors++;
}
}
if (ASSERT_REGISTER_ERRORS)
assert(errors == 0);
}
void Block::regArrayCheck (RegisterArray *r)
{
int errors = 0;
Addr thisStart = r->getStartAddr();
Addr thisEnd = r->getEndAddr();
Addr thisStep = r->getStep();
uint thisCount = r->getCount();
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem()) {
Addr regAddr = reg->getAddr();
if (regAddr >= thisStart && regAddr <= thisEnd &&
((regAddr - thisStart) % thisStep) == 0) {
cerr << "WARNING: " << r->getFullName()
<< " at 0x" << hex << thisStart << " to 0x" << thisEnd
<< " step 0x" << thisStep
<< " overlaps with " << reg->getFullName()
<< " at 0x" << regAddr << "\n" << dec;
errors++;
}
}
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem()) {
Addr arrayStart = regArray->getStartAddr();
Addr arrayEnd = regArray->getEndAddr();
Addr arrayStep = regArray->getStep();
uint arrayCount = regArray->getCount();
if (arrayStart <= thisEnd &&
arrayEnd >= thisStart) {
bool overlap = false;
if (arrayCount > thisCount) {
for (Addr regAddr=arrayStart; regAddr<=arrayEnd; regAddr+=arrayStep) {
if (regAddr >= thisStart && regAddr <= thisEnd &&
((regAddr - thisStart) % thisStep) == 0) {
overlap = true;
break;
}
}
} else {
for (Addr thisAddr=thisStart; thisAddr<=thisEnd; thisAddr+=thisStep) {
if (thisAddr >= arrayStart && thisAddr <= arrayEnd &&
((thisAddr - arrayStart) % arrayStep) == 0) {
overlap = true;
break;
}
}
}
if (overlap) {
cerr << "WARNING: " << r->getFullName()
<< " at 0x" << hex << thisStart << " to 0x" << thisEnd
<< " step 0x" << thisStep
<< " overlaps with " << regArray->getFullName()
<< " at 0x" << arrayStart << " to 0x" << arrayEnd
<< " step 0x" << arrayStep << "\n" << dec;
errors++;
}
}
}
if (ASSERT_REGISTER_ERRORS)
assert(errors == 0);
}
bool Block::regRead (Addr a, Data *d)
{
Register *reg;
if ((reg = regLookup(a)) != NULL) {
*d = reg->read();
if (VERBOSE_REGISTER) {
cout << "Read value 0x" << hex << *d
<< " from " << reg->getFullName()
<< " at address 0x" << a << "\n";
}
return true;
} else {
if (VERBOSE_REGISTER) {
cout << "Read register at invalid address 0x" << hex << a << "\n";
}
return false;
}
}
Register *Block::regLookup (Addr a)
{
uint count = 0;
if (a >= minAddr && a <= maxAddr) {
Register *mapReg = NULL;
if (map != NULL && (mapReg = map->lookup(a)) != NULL) {
assert(mapReg->getAddr() == a);
if (VERBOSE_LOOKUP) {
cout << "Lookup for register " << mapReg->getFullName() << " has "
<< dec << count << " checks in block " << getFullName()
<< " (map found)\n";
}
if (!MAP_CHECK)
return mapReg;
}
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem()) {
count++;
if (reg->getAddr() == a) {
if (VERBOSE_LOOKUP) {
cout << "Lookup for register " << reg->getFullName() << " has "
<< dec << count << " checks in block " << getFullName()
<< " (found)\n";
}
if (MAP_CHECK && mapReg != NULL)
assert(mapReg->getPtr() == reg->getPtr());
return reg;
}
}
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem()) {
Addr startAddr = regArray->getStartAddr();
Addr endAddr = regArray->getEndAddr();
Addr step = regArray->getStep();
count++;
if (a >= startAddr && a <= endAddr &&
((a - startAddr) % step) == 0) {
uint64 index = (a - startAddr) / step;
assert(index < regArray->getCount());
uint i = uint(index);
if (VERBOSE_LOOKUP) {
cout << "Lookup for register " << (*regArray)[i].getFullName()
<< " has " << dec << count << " checks in block "
<< getFullName() << " (found)\n";
}
if (MAP_CHECK && mapReg != NULL)
assert(mapReg->getPtr() == (*regArray)[i].getPtr());
return &(*regArray)[i];
}
}
}
if (VERBOSE_LOOKUP) {
cout << "Lookup for address 0x" << hex << a << " has " << dec << count
<< " checks in block " << getFullName() << " (not found)\n";
}
return NULL;
}
Register *Block::regLookup (string n)
{
uint count = 0;
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem()) {
count++;
if (reg->getBaseName() == n) {
if (VERBOSE_LOOKUP) {
cout << "Lookup for register " << reg->getFullName() << " has "
<< dec << count << " checks in block " << getFullName()
<< " (found)\n";
}
return reg;
}
}
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem()) {
count++;
string basename = regArray->getBaseName();
long baselen = basename.length();
long nlen = n.length();
if (nlen >= baselen + 3 &&
basename.compare(0, baselen, n, 0, baselen) == 0 &&
n[baselen] == '[' &&
n[nlen - 1] == ']') {
uint index = 0;
bool ok = true;
for (uint i=baselen+1; ok && i < nlen-1; i++) {
if (isdigit(n[i]))
index = 10 * index + (n[i] - '0');
else
ok = false;
}
if (ok && index < regArray->getCount()) {
if (VERBOSE_LOOKUP) {
cout << "Lookup for register " << (*regArray)[index].getFullName()
<< " has " << dec << count << " checks in block "
<< getFullName() << " (found)\n";
}
return &(*regArray)[index];
}
}
}
if (VERBOSE_LOOKUP) {
cout << "Lookup for register " << n << " has " << dec << count
<< " checks in block " << getFullName() << " (not found)\n";
}
return NULL;
}
bool Block::regRead (string n, Data *d)
{
Register *reg;
if ((reg = regLookup(n)) != NULL) {
*d = reg->read();
if (VERBOSE_REGISTER) {
cout << "Read value 0x" << hex << *d
<< " from " << reg->getFullName()
<< " at address 0x" << reg->getAddr() << "\n";
}
return true;
} else {
if (VERBOSE_REGISTER) {
cout << "Read register with invalid name " << n << "\n";
}
return false;
}
}
bool Block::regWrite (Addr a, Data d)
{
Register *reg;
if ((reg = regLookup(a)) != NULL) {
reg->write(d);
if (VERBOSE_REGISTER) {
cout << "Write value 0x" << hex << d
<< " to " << reg->getFullName()
<< " at address 0x" << a << "\n";
}
return true;
} else {
if (VERBOSE_REGISTER) {
cout << "Write register at invalid address 0x" << hex << a << "\n";
}
return false;
}
}
bool Block::regWrite (string n, Data d)
{
Register *reg;
if ((reg = regLookup(n)) != NULL) {
reg->write(d);
if (VERBOSE_REGISTER) {
cout << "Write value 0x" << hex << d
<< " to " << reg->getFullName()
<< " at address 0x" << reg->getAddr() << "\n";
}
return true;
} else {
if (VERBOSE_REGISTER) {
cout << "Write register with invalid name " << n << "\n";
}
return false;
}
}
void Block::enableWriteBlockCB ()
{
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem())
reg->enableWriteBlockCB();
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem())
regArray->enableWriteBlockCB();
}
void Block::disableWriteBlockCB ()
{
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem())
reg->disableWriteBlockCB();
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem())
regArray->disableWriteBlockCB();
}
void Block::enableReadBlockCB ()
{
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem())
reg->enableReadBlockCB();
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem())
regArray->enableReadBlockCB();
}
void Block::disableReadBlockCB ()
{
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem())
reg->disableReadBlockCB();
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem())
regArray->disableReadBlockCB();
}
void Block::printThis (ostream &os)
{
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem())
reg->printThis(os);
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem())
regArray->printThis(os);
}
void Block::resetThis ()
{
finalize();
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem())
reg->resetThis();
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem())
regArray->resetThis();
}
void Block::finalize ()
{
if (!final) {
final = true;
// Map construction is postponed to Block::finalize(). The reason
// for this is that the Register indexing and cloning for mapping
// of each RegisterArray relies on virtual methods to use the
// appropriate index and clone methods of the specific RegisterArray
// subclass. Virtual overloading does not work during construction
// and this has to be postponed until later, and this is the first
// convenient point. If there is any use of regLookup, regRead or
// regWrite prior to finalization, then these methods will behave
// correctly but there is no mapping optimization - this should
// not be a performance problem.
if (MAP_ENABLE && map == NULL) {
map = new Map<Register>(getFullName());
}
uint countReg = 0;
ListIterator<Register> regIter(&registers);
for (Register *reg = regIter.getHeadItem();
reg != NULL;
reg = regIter.getNextItem()) {
if (MAP_ENABLE && reg->getWidth() == 8) {
bool ok = map->insert(reg->getAddr(), reg);
if (ASSERT_REGISTER_ERRORS)
assert(ok);
}
countReg++;
}
uint countRegArray = 0;
ListIterator<RegisterArray> regArrayIter(&registerArrays);
for (RegisterArray *regArray = regArrayIter.getHeadItem();
regArray != NULL;
regArray = regArrayIter.getNextItem()) {
if (MAP_ENABLE && regArray->getWidth() == 8 && !regArray->isHuge()) {
uint count = regArray->getCount();
for (uint index=0; index<count; index++) {
Register &src = (*regArray)[index];
Register *reg = src.clone();
bool ok = map->insert(reg->getAddr(), reg);
if (ASSERT_REGISTER_ERRORS)
assert(ok);
}
}
countRegArray++;
}
if (VERBOSE_BLOCK) {
cout << "Block " << getFullName() << " has " << dec
<< countReg << " registers and "
<< countRegArray << " register arrays\n";
if (countReg + countRegArray > 0) {
cout << "Block " << getFullName() << " has " << hex
<< "registers in range 0x" << minAddr << " to " << maxAddr
<< " covering " << dec << maxAddr - minAddr << " bytes\n";
}
}
}
}