Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / regdef / Register.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: Register.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 <iostream>
#include <stdlib.h>
#include <assert.h>
#include "Object.h"
#include "Register.h"
#include "Signature.h"
using namespace std;
static const bool ASSERT_REGISTER_ERRORS = false;
RegisterType::RegisterType (uint w)
{
assert(w == 1 || w == 2 || w == 4 || w == 8);
widthBytes = w;
widthBits = w << 3;
widthMask = (widthBits == 64) ? ~Data(0) : (Data(1) << widthBits) - 1;
checkMask = 0;
writeMask = 0;
writeOneToClearMask = 0;
writeOneToSetMask = 0;
readMask = 0;
readAsUndefinedMask = 0;
readAsZeroMask = 0;
readToClearMask = 0;
resetValue = UNDEFINED_DATA & widthMask;
resetAssigned = 0;
writeBlockCB = false;
readBlockCB = false;
}
void RegisterType::check (string n)
{
// cerr << hex << "check " << n << " " << checkMask << " " << widthMask << " " << endl;
if (checkMask != widthMask) {
assert((checkMask & ~widthMask) == 0);
int errors = 0;
for (uint i=0; i<widthBits; i++) {
if ((checkMask & (1ULL << i)) == 0) {
int start = i;
for (i++; i<widthBits; i++) {
if ((checkMask & (1ULL << i)) != 0)
break;
}
int end = i-1;
cerr << "WARNING: Register bits " << n
<< "[" << end << ":" << start << "]"
<< " do not belong to any field\n";
errors++;
}
}
if (ASSERT_REGISTER_ERRORS)
assert(errors == 0);
}
}
Register::Register ()
{
baseName = "";
block = NULL;
addr = 0;
derived = false;
element = false;
index = 0;
regType = NULL;
regState = NULL;
regInfo = NULL;
mySignature = NULL;
}
Register::Register (string n, Block *b, Addr a, uint w)
{
baseName = n;
block = b;
addr = a;
derived = false;
element = false;
index = 0;
regType = new RegisterType(w);
regState = new RegisterState(UNDEFINED_DATA); // undefined value
regInfo = new RegisterInfo(false, false); // unassigned and dirty
mySignature = NULL;
// cerr << "REG " << n << hex << " chk " << regType->checkMask << " width " << regType->widthMask << endl;
if (b != NULL) {
// The address is only used/checked when the Register has a Block
assert((a % regType->widthBytes) == 0);
b->addRegister(this);
}
}
Register::Register (const Register &r)
{
baseName = r.baseName;
block = r.block;
addr = r.addr;
derived = true;
element = r.element;
index = r.index;
regType = r.regType;
regState = r.regState;
regInfo = r.regInfo;
mySignature = r.mySignature;
}
Register::~Register ()
{
if (!derived) {
delete regType;
delete regState;
delete regInfo;
delete mySignature;
}
}
void Register::init (Block *b, Addr a, bool e, uint i, RegisterType *rt,
RegisterState *rs, RegisterInfo *ri, Signature *s)
{
assert(rt != NULL && rs != NULL && ri != NULL);
assert((a % rt->widthBytes) == 0);
block = b;
addr = a;
derived = true;
element = e;
index = i;
regType = rt;
regState = rs;
regInfo = ri;
mySignature = s;
}
Register &Register::operator= (const Register &r)
{
if (this != &r) {
if (!derived) {
delete regType;
delete regState;
delete regInfo;
delete mySignature;
}
baseName = r.baseName;
block = r.block;
addr = r.addr;
derived = true;
element = r.element;
index = r.index;
regType = r.regType;
regState = r.regState;
regInfo = r.regInfo;
mySignature = r.mySignature;
}
return *this;
}
string Register::getBaseName() const
{
if (element) {
ostringstream o;
o << index;
return baseName + "[" + o.str() + "]";
}
else
return baseName;
}
string Register::getFullName() const
{
return (block == NULL) ? getBaseName()
: block->getFullName() + "." + getBaseName();
}
void Register::printThis (ostream &os)
{
os << getFullName() << " (0x" << hex << addr
<< ", width " << dec << regType->widthBytes << " bytes) = 0x"
<< hex << regState->value << "\n" << dec;
ListIterator<FieldType> iter(&regType->fieldTypes);
for (FieldType *fieldType = iter.getHeadItem();
fieldType != NULL;
fieldType = iter.getNextItem()) {
Data v = (regState->value >> fieldType->start) & fieldType->fieldMask;
string s = fieldType->getAccessType();
if ( v != 0 )
os << "\t" << getFullName() << "." << fieldType->getBaseName()
<< " (" << dec << fieldType->end << ":" << fieldType->start
<< ") = 0x" << hex << v << " (" << s << ")\n" << dec;
}
}
void Register::resetThis ()
{
regType->check(getFullName());
regState->value = regType->resetValue;
regInfo->assigned = (regType->resetAssigned != 0);
regInfo->clean = false;
}
void Register::signThis (ofstream &ofs)
{
regType->check(getFullName());
mySignature = new Signature;
mySignature->add(new SignData(getFullName(), "", &regState->value));
mySignature->sign(ofs, getBaseName(), "Register");
}
void Register::traceThis (ofstream &ofs)
{
if (mySignature && !regInfo->clean) {
mySignature->printThis(ofs);
regInfo->clean = true;
}
}
FieldType::FieldType (string f, string n, RegisterType *r, AccessType a,
uint e, uint s, bool b, Data d)
{
assert(a == Access_RO || a == Access_RW || a == Access_RC ||
a == Access_RW1C || a == Access_RW1S ||
a == Access_RCW1C || a == Access_RCW1S ||
a == Access_WO || a == Access_L);
d = b ? d : (UNDEFINED_DATA >> s);
baseName = n;
if (s > e) {
cerr << "WARNING: Register field " << f << "." << n
<< "[" << e << ":" << s << "]"
<< " has inverted field positions\n";
int t = e;
e = s;
s = t;
}
if (e >= r->widthBits) {
cerr << "WARNING: Register field " << f << "." << n
<< "[" << e << ":" << s << "]"
<< " has out of range end position\n";
e = r->widthBits - 1;
}
assert(s <= e && e < r->widthBits);
access = a;
start = s;
end = e;
if (e == 63)
regMask = - (Data(1) << s);
else
regMask = (Data(1) << (e+1)) - (Data(1) << s);
fieldMask = regMask >> s;
resetValue = d & fieldMask;
regType = r;
regType->fieldTypes.addTail(this);
regType->resetValue = (regType->resetValue & ~regMask) |
(resetValue << start);
if (b)
regType->resetAssigned |= regMask;
regType->checkMask |= regMask;
// cerr << "reg " << n << " field " << f << " s " << s << " e " << e << " chk " << hex << regType->checkMask << " width " << regType->widthMask << endl;
if (a == Access_RW1C || a == Access_RCW1C)
regType->writeOneToClearMask |= regMask;
else if (a == Access_RW1S || a == Access_RCW1S)
regType->writeOneToSetMask |= regMask;
else if (a != Access_RO)
regType->writeMask |= regMask;
if (a == Access_WO)
regType->readAsUndefinedMask |= regMask;
else if (a == Access_L)
regType->readAsZeroMask |= regMask;
else
regType->readMask |= regMask;
if (a == Access_RC || a == Access_RCW1C || a == Access_RCW1S)
regType->readToClearMask |= regMask;
}
string FieldType::getAccessType () const
{
switch (access) {
case Access_RC: return "RC";
case Access_RO: return "RO";
case Access_RW: return "R/W";
case Access_RW1C: return "R/W1C";
case Access_RW1S: return "R/W1S";
case Access_RCW1C: return "RC/W1C";
case Access_RCW1S: return "RC/W1S";
case Access_WO: return "WO";
case Access_L: return "L";
default: assert(0); return "";
}
}
bool FieldType::overlap (FieldType *f)
{
return (regMask & f->regMask) != 0;
}
void FieldType::check (RegisterType *r, string n)
{
int errors = 0;
ListIterator<FieldType> iter(&r->fieldTypes);
for (FieldType *fieldType = iter.getHeadItem();
fieldType != NULL;
fieldType = iter.getNextItem()) {
if (fieldType != this && overlap(fieldType)) {
cerr << "WARNING: Register field " << n
<< "[" << end << ":" << start << "]"
<< " overlaps with existing field "
<< fieldType->getBaseName() << "\n";
errors++;
}
}
if (ASSERT_REGISTER_ERRORS)
assert(errors == 0);
}
Field::Field ()
{
derived = false;
reg = NULL;
fieldType = NULL;
}
Field::Field (string n, Register *r, AccessType a,
uint e, uint s, bool b, Data d)
{
assert(r != NULL);
derived = false;
reg = r;
fieldType = new FieldType(r->getFullName(), n, r->regType, a, e, s, b, d);
fieldType->check(r->regType, getFullName());
}
Field::Field (const Field &f)
{
derived = true;
reg = f.reg;
fieldType = f.fieldType;
}
Field::~Field ()
{
if (!derived)
delete fieldType;
}
Field &Field::operator= (const Field &f)
{
if (this != &f) {
if (!derived)
delete fieldType;
derived = true;
reg = f.reg;
fieldType = f.fieldType;
}
return *this;
}
string Field::getBaseName() const
{
return fieldType->getBaseName();
}
string Field::getFullName() const
{
return reg->getFullName() + "." + getBaseName();
;
}